blob: 7a25e69992c74a06fb4ae9f5ca0b9090b3648b5c [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";
1181
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001182 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1183
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001184 // special varyings that use reserved registers
1185 int reservedRegisterIndex = registers;
1186 std::string fragCoordSemantic;
1187 std::string pointCoordSemantic;
1188
1189 if (fragmentShader->mUsesFragCoord)
1190 {
1191 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1192 }
1193
1194 if (fragmentShader->mUsesPointCoord)
1195 {
1196 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1197 // In DX11 we compute this in the GS.
1198 if (shaderModel == 3)
1199 {
1200 pointCoordSemantic = "TEXCOORD0";
1201 }
1202 else if (shaderModel >= 4)
1203 {
1204 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1205 }
1206 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001207
1208 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001209 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001210
1211 int semanticIndex = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04001212 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
1213 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001214 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001215 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1216 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1217 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001218
Jamie Madilldefb6742013-06-20 11:55:51 -04001219 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001220 }
1221
1222 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001223 "\n"
1224 "struct VS_OUTPUT\n"
1225 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001226
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001227 if (shaderModel < 4)
1228 {
1229 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1230 }
1231
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001232 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001233
1234 if (fragmentShader->mUsesFragCoord)
1235 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001236 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001237 }
1238
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001239 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001240 {
1241 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1242 }
1243
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001244 if (shaderModel >= 4)
1245 {
1246 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1247 }
1248
1249 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001250 "\n"
1251 "VS_OUTPUT main(VS_INPUT input)\n"
1252 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001253
Jamie Madilldefb6742013-06-20 11:55:51 -04001254 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001255 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001256 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1257 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001258
Jamie Madilldefb6742013-06-20 11:55:51 -04001259 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001260 {
1261 vertexHLSL += "transpose";
1262 }
1263
Jamie Madilldefb6742013-06-20 11:55:51 -04001264 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001265 }
1266
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001267 if (shaderModel >= 4)
1268 {
1269 vertexHLSL += "\n"
1270 " gl_main();\n"
1271 "\n"
1272 " VS_OUTPUT output;\n"
1273 " output.gl_Position.x = gl_Position.x;\n"
1274 " output.gl_Position.y = -gl_Position.y;\n"
1275 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1276 " output.gl_Position.w = gl_Position.w;\n";
1277 }
1278 else
1279 {
1280 vertexHLSL += "\n"
1281 " gl_main();\n"
1282 "\n"
1283 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001284 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1285 " 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 +00001286 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1287 " output.gl_Position.w = gl_Position.w;\n";
1288 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001289
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001290 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001291 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001292 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001293 }
1294
1295 if (fragmentShader->mUsesFragCoord)
1296 {
1297 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1298 }
1299
1300 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1301 {
1302 if (varying->reg >= 0)
1303 {
1304 for (int i = 0; i < varying->size; i++)
1305 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001306 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001307
1308 for (int j = 0; j < rows; j++)
1309 {
1310 int r = varying->reg + i * rows + j;
1311 vertexHLSL += " output.v" + str(r);
1312
1313 bool sharedRegister = false; // Register used by multiple varyings
1314
1315 for (int x = 0; x < 4; x++)
1316 {
1317 if (packing[r][x] && packing[r][x] != packing[r][0])
1318 {
1319 sharedRegister = true;
1320 break;
1321 }
1322 }
1323
1324 if(sharedRegister)
1325 {
1326 vertexHLSL += ".";
1327
1328 for (int x = 0; x < 4; x++)
1329 {
1330 if (packing[r][x] == &*varying)
1331 {
1332 switch(x)
1333 {
1334 case 0: vertexHLSL += "x"; break;
1335 case 1: vertexHLSL += "y"; break;
1336 case 2: vertexHLSL += "z"; break;
1337 case 3: vertexHLSL += "w"; break;
1338 }
1339 }
1340 }
1341 }
1342
1343 vertexHLSL += " = " + varying->name;
1344
1345 if (varying->array)
1346 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001347 vertexHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001348 }
1349
1350 if (rows > 1)
1351 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001352 vertexHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001353 }
1354
1355 vertexHLSL += ";\n";
1356 }
1357 }
1358 }
1359 }
1360
1361 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001362 " return output;\n"
1363 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001364
1365 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001366 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001367
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001368 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001369
1370 if (fragmentShader->mUsesFragCoord)
1371 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001372 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001373 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001374
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001375 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1376 {
1377 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1378 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001379
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001380 // Must consume the PSIZE element if the geometry shader is not active
1381 // We won't know if we use a GS until we draw
1382 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1383 {
1384 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1385 }
1386
1387 if (fragmentShader->mUsesFragCoord)
1388 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001389 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001390 {
1391 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1392 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001393 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001394 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001395 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1396 }
1397 }
1398
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001399 pixelHLSL += "};\n"
1400 "\n"
1401 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001402 "{\n";
1403
Jamie Madill46131a32013-06-20 11:55:50 -04001404 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001405 {
Jamie Madill46131a32013-06-20 11:55:50 -04001406 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1407 {
1408 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1409 }
1410 }
1411 else
1412 {
1413 defineOutputVariables(fragmentShader);
1414
1415 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1416 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1417 {
1418 const VariableLocation &outputLocation = locationIt->second;
1419 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1420 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1421
1422 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1423 " out_" + outputLocation.name + elementString +
1424 " : " + targetSemantic + str(locationIt->first) + ";\n";
1425 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001426 }
1427
1428 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001429 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001430
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001431 if (fragmentShader->mUsesFrontFacing)
1432 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001433 if (shaderModel >= 4)
1434 {
1435 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1436 "{\n";
1437 }
1438 else
1439 {
1440 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1441 "{\n";
1442 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001443 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001444 else
1445 {
1446 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1447 "{\n";
1448 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001449
1450 if (fragmentShader->mUsesFragCoord)
1451 {
1452 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1453
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001454 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001455 {
1456 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1457 " gl_FragCoord.y = input.dx_VPos.y;\n";
1458 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001459 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001460 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001461 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001462 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001463 }
1464 else
1465 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001466 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1467 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1468 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001469 }
1470
daniel@transgaming.com12985182012-12-20 20:56:31 +00001471 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001472 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001473 }
1474
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001475 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001476 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001477 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1478 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001479 }
1480
1481 if (fragmentShader->mUsesFrontFacing)
1482 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001483 if (shaderModel <= 3)
1484 {
1485 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1486 }
1487 else
1488 {
1489 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1490 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001491 }
1492
1493 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1494 {
1495 if (varying->reg >= 0)
1496 {
1497 for (int i = 0; i < varying->size; i++)
1498 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001499 GLenum transposedType = TransposeMatrixType(varying->type);
1500 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001501 for (int j = 0; j < rows; j++)
1502 {
1503 std::string n = str(varying->reg + i * rows + j);
1504 pixelHLSL += " " + varying->name;
1505
1506 if (varying->array)
1507 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001508 pixelHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001509 }
1510
1511 if (rows > 1)
1512 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001513 pixelHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001514 }
1515
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001516 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001517 {
1518 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1519 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1520 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1521 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1522 default: UNREACHABLE();
1523 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001524 }
1525 }
1526 }
1527 else UNREACHABLE();
1528 }
1529
1530 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001531 " gl_main();\n"
1532 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001533 " PS_OUTPUT output;\n";
1534
Jamie Madill46131a32013-06-20 11:55:50 -04001535 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001536 {
Jamie Madill46131a32013-06-20 11:55:50 -04001537 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1538 {
1539 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001540
Jamie Madill46131a32013-06-20 11:55:50 -04001541 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1542 }
1543 }
1544 else
1545 {
1546 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1547 {
1548 const VariableLocation &outputLocation = locationIt->second;
1549 const std::string &variableName = "out_" + outputLocation.name;
1550 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1551 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1552
1553 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1554 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001555 }
1556
1557 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001558 " return output;\n"
1559 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001560
1561 return true;
1562}
1563
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001564std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1565{
1566 std::string varyingHLSL;
1567
1568 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1569 {
1570 if (varying->reg >= 0)
1571 {
1572 for (int i = 0; i < varying->size; i++)
1573 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001574 GLenum transposedType = TransposeMatrixType(varying->type);
1575 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001576 for (int j = 0; j < rows; j++)
1577 {
1578 switch (varying->interpolation)
1579 {
1580 case Smooth: varyingHLSL += " "; break;
1581 case Flat: varyingHLSL += " nointerpolation "; break;
1582 case Centroid: varyingHLSL += " centroid "; break;
1583 default: UNREACHABLE();
1584 }
1585
1586 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001587 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001588
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001589 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001590 }
1591 }
1592 }
1593 else UNREACHABLE();
1594 }
1595
1596 return varyingHLSL;
1597}
1598
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001599bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1600{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001601 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001602
1603 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001604 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605 if (format != GL_PROGRAM_BINARY_ANGLE)
1606 {
1607 infoLog.append("Invalid program binary format.");
1608 return false;
1609 }
1610
1611 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001612 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001613 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614 {
1615 infoLog.append("Invalid program binary version.");
1616 return false;
1617 }
1618
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001619 int compileFlags = 0;
1620 stream.read(&compileFlags);
1621 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1622 {
1623 infoLog.append("Mismatched compilation flags.");
1624 return false;
1625 }
1626
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1628 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001629 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001630 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.read(&name);
1632 mLinkedAttribute[i].name = name;
1633 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 }
1635
1636 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1637 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001638 stream.read(&mSamplersPS[i].active);
1639 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640
1641 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001642 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643 mSamplersPS[i].textureType = (TextureType) textureType;
1644 }
1645
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001646 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001647 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001648 stream.read(&mSamplersVS[i].active);
1649 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001650
1651 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001652 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001653 mSamplersVS[i].textureType = (TextureType) textureType;
1654 }
1655
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001656 stream.read(&mUsedVertexSamplerRange);
1657 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001658 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001659 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001661 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001662 stream.read(&size);
1663 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664 {
1665 infoLog.append("Invalid program binary.");
1666 return false;
1667 }
1668
1669 mUniforms.resize(size);
1670 for (unsigned int i = 0; i < size; ++i)
1671 {
1672 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001673 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001674 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001676 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001677
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001679 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001680 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001682 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001684 int offset;
1685 int arrayStride;
1686 int matrixStride;
1687 bool isRowMajorMatrix;
1688
1689 stream.read(&offset);
1690 stream.read(&arrayStride);
1691 stream.read(&matrixStride);
1692 stream.read(&isRowMajorMatrix);
1693
1694 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1695
1696 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001698 stream.read(&mUniforms[i]->psRegisterIndex);
1699 stream.read(&mUniforms[i]->vsRegisterIndex);
1700 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001701 }
1702
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001703 stream.read(&size);
1704 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705 {
1706 infoLog.append("Invalid program binary.");
1707 return false;
1708 }
1709
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001710 mUniformBlocks.resize(size);
1711 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1712 {
1713 std::string name;
1714 unsigned int elementIndex;
1715 unsigned int dataSize;
1716
1717 stream.read(&name);
1718 stream.read(&elementIndex);
1719 stream.read(&dataSize);
1720
1721 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1722
1723 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1724 stream.read(&uniformBlock.psRegisterIndex);
1725 stream.read(&uniformBlock.vsRegisterIndex);
1726
1727 size_t numMembers;
1728 stream.read(&numMembers);
1729 uniformBlock.memberUniformIndexes.resize(numMembers);
1730 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1731 {
1732 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1733 }
1734 }
1735
1736 stream.read(&size);
1737 if (stream.error())
1738 {
1739 infoLog.append("Invalid program binary.");
1740 return false;
1741 }
1742
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743 mUniformIndex.resize(size);
1744 for (unsigned int i = 0; i < size; ++i)
1745 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001746 stream.read(&mUniformIndex[i].name);
1747 stream.read(&mUniformIndex[i].element);
1748 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001749 }
1750
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001752 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001753
1754 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001755 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001756
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001757 unsigned int geometryShaderSize;
1758 stream.read(&geometryShaderSize);
1759
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001760 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001761
daniel@transgaming.com36038542012-11-28 20:59:26 +00001762 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763 ptr += sizeof(GUID);
1764
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001765 GUID identifier = mRenderer->getAdapterIdentifier();
1766 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767 {
1768 infoLog.append("Invalid program binary.");
1769 return false;
1770 }
1771
1772 const char *pixelShaderFunction = ptr;
1773 ptr += pixelShaderSize;
1774
1775 const char *vertexShaderFunction = ptr;
1776 ptr += vertexShaderSize;
1777
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001778 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1779 ptr += geometryShaderSize;
1780
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001781 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001782 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001783 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001784 {
1785 infoLog.append("Could not create pixel shader.");
1786 return false;
1787 }
1788
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001789 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001790 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001791 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001792 {
1793 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001794 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001795 mPixelExecutable = NULL;
1796 return false;
1797 }
1798
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001799 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1800 {
1801 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1802 geometryShaderSize, rx::SHADER_GEOMETRY);
1803 if (!mGeometryExecutable)
1804 {
1805 infoLog.append("Could not create geometry shader.");
1806 delete mPixelExecutable;
1807 mPixelExecutable = NULL;
1808 delete mVertexExecutable;
1809 mVertexExecutable = NULL;
1810 return false;
1811 }
1812 }
1813 else
1814 {
1815 mGeometryExecutable = NULL;
1816 }
1817
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001818 return true;
1819}
1820
1821bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1822{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001823 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001826 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001827 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001828
1829 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1830 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001831 stream.write(mLinkedAttribute[i].type);
1832 stream.write(mLinkedAttribute[i].name);
1833 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834 }
1835
1836 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1837 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001838 stream.write(mSamplersPS[i].active);
1839 stream.write(mSamplersPS[i].logicalTextureUnit);
1840 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001841 }
1842
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001843 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001844 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001845 stream.write(mSamplersVS[i].active);
1846 stream.write(mSamplersVS[i].logicalTextureUnit);
1847 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001848 }
1849
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001850 stream.write(mUsedVertexSamplerRange);
1851 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001852 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001853 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001855 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001856 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001858 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001859
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001860 stream.write(uniform.type);
1861 stream.write(uniform.precision);
1862 stream.write(uniform.name);
1863 stream.write(uniform.arraySize);
1864 stream.write(uniform.blockIndex);
1865
1866 stream.write(uniform.blockInfo.offset);
1867 stream.write(uniform.blockInfo.arrayStride);
1868 stream.write(uniform.blockInfo.matrixStride);
1869 stream.write(uniform.blockInfo.isRowMajorMatrix);
1870
1871 stream.write(uniform.psRegisterIndex);
1872 stream.write(uniform.vsRegisterIndex);
1873 stream.write(uniform.registerCount);
1874 }
1875
1876 stream.write(mUniformBlocks.size());
1877 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1878 {
1879 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1880
1881 stream.write(uniformBlock.name);
1882 stream.write(uniformBlock.elementIndex);
1883 stream.write(uniformBlock.dataSize);
1884
1885 stream.write(uniformBlock.memberUniformIndexes.size());
1886 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1887 {
1888 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1889 }
1890
1891 stream.write(uniformBlock.psRegisterIndex);
1892 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001893 }
1894
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001895 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001896 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1897 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001898 stream.write(mUniformIndex[i].name);
1899 stream.write(mUniformIndex[i].element);
1900 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001901 }
1902
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001903 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001904 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001905
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001906 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001907 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001908
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001909 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1910 stream.write(geometryShaderSize);
1911
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001912 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001913
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001914 GLsizei streamLength = stream.length();
1915 const void *streamData = stream.data();
1916
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001917 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001918 if (totalLength > bufSize)
1919 {
1920 if (length)
1921 {
1922 *length = 0;
1923 }
1924
1925 return false;
1926 }
1927
1928 if (binary)
1929 {
1930 char *ptr = (char*) binary;
1931
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001932 memcpy(ptr, streamData, streamLength);
1933 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001934
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001935 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001936 ptr += sizeof(GUID);
1937
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001938 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001939 ptr += pixelShaderSize;
1940
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001941 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001942 ptr += vertexShaderSize;
1943
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001944 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1945 {
1946 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1947 ptr += geometryShaderSize;
1948 }
1949
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001950 ASSERT(ptr - totalLength == binary);
1951 }
1952
1953 if (length)
1954 {
1955 *length = totalLength;
1956 }
1957
1958 return true;
1959}
1960
1961GLint ProgramBinary::getLength()
1962{
1963 GLint length;
1964 if (save(NULL, INT_MAX, &length))
1965 {
1966 return length;
1967 }
1968 else
1969 {
1970 return 0;
1971 }
1972}
1973
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001974bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001975{
1976 if (!fragmentShader || !fragmentShader->isCompiled())
1977 {
1978 return false;
1979 }
1980
1981 if (!vertexShader || !vertexShader->isCompiled())
1982 {
1983 return false;
1984 }
1985
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001986 mShaderVersion = vertexShader->getShaderVersion();
1987
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001988 std::string pixelHLSL = fragmentShader->getHLSL();
1989 std::string vertexHLSL = vertexShader->getHLSL();
1990
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001991 // Map the varyings to the register file
1992 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1993 int registers = packVaryings(infoLog, packing, fragmentShader);
1994
1995 if (registers < 0)
1996 {
1997 return false;
1998 }
1999
2000 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002001 {
2002 return false;
2003 }
2004
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002005 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002006
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002007 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2008 {
2009 success = false;
2010 }
2011
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002012 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002013 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002014 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002015 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002016
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002017 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2018 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2019 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002020 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2021 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2022 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 +00002023 }
2024
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002025 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2026 {
2027 success = false;
2028 }
2029
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002030 if (success)
2031 {
2032 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
2033 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
2034
2035 if (usesGeometryShader())
2036 {
2037 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2038 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2039 }
2040
2041 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
2042 {
2043 infoLog.append("Failed to create D3D shaders.");
2044 success = false;
2045
2046 delete mVertexExecutable;
2047 mVertexExecutable = NULL;
2048 delete mPixelExecutable;
2049 mPixelExecutable = NULL;
2050 delete mGeometryExecutable;
2051 mGeometryExecutable = NULL;
2052 }
2053 }
2054
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002055 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002056}
2057
2058// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002059bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002060{
2061 unsigned int usedLocations = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04002062 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002063
2064 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002065 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002066 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002067 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002068 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002069
Jamie Madilleba4eff2013-06-20 11:55:51 -04002070 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002072 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002073
2074 if (rows + location > MAX_VERTEX_ATTRIBS)
2075 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002076 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 +00002077
2078 return false;
2079 }
2080
Jamie Madilleba4eff2013-06-20 11:55:51 -04002081 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002083 const int rowLocation = location + row;
2084 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2085
2086 // In GLSL 3.00, attribute aliasing produces a link error
2087 // In GLSL 1.00, attribute aliasing is allowed
2088 if (mShaderVersion >= 300)
2089 {
2090 if (!linkedAttribute.name.empty())
2091 {
2092 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2093 return false;
2094 }
2095 }
2096
2097 linkedAttribute = attribute;
2098 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002099 }
2100 }
2101 }
2102
2103 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002104 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002105 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002106 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002107 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002108
Jamie Madilleba4eff2013-06-20 11:55:51 -04002109 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002110 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002111 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002112 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2113
2114 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2115 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002116 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002117
2118 return false; // Fail to link
2119 }
2120
Jamie Madilldefb6742013-06-20 11:55:51 -04002121 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002122 }
2123 }
2124
2125 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2126 {
2127 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002128 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002129
2130 for (int r = 0; r < rows; r++)
2131 {
2132 mSemanticIndex[attributeIndex++] = index++;
2133 }
2134 }
2135
2136 return true;
2137}
2138
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002139bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2140{
2141 if (vertexUniform.type != fragmentUniform.type)
2142 {
2143 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2144 return false;
2145 }
2146 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2147 {
2148 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2149 return false;
2150 }
2151 else if (vertexUniform.precision != fragmentUniform.precision)
2152 {
2153 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2154 return false;
2155 }
2156 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2157 {
2158 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2159 }
Jamie Madill010fffa2013-06-20 11:55:53 -04002160 else if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2161 {
2162 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2163 return false;
2164 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002165
2166 const unsigned int numMembers = vertexUniform.fields.size();
2167 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2168 {
2169 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2170 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2171
2172 if (vertexMember.name != fragmentMember.name)
2173 {
2174 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2175 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2176 return false;
2177 }
2178
2179 const std::string memberName = uniformName + "." + vertexUniform.name;
2180 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2181 {
2182 return false;
2183 }
2184 }
2185
2186 return true;
2187}
2188
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002189bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002190{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002191 // Check that uniforms defined in the vertex and fragment shaders are identical
2192 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2193 UniformMap linkedUniforms;
2194
2195 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2196 {
2197 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2198 linkedUniforms[vertexUniform.name] = &vertexUniform;
2199 }
2200
2201 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2202 {
2203 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2204 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2205 if (entry != linkedUniforms.end())
2206 {
2207 const sh::Uniform &vertexUniform = *entry->second;
2208 const std::string &uniformName = "uniform " + vertexUniform.name;
2209 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2210 {
2211 return false;
2212 }
2213 }
2214 }
2215
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002216 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002217 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002218 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002219 {
2220 return false;
2221 }
2222 }
2223
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002224 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002225 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002226 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002227 {
2228 return false;
2229 }
2230 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002231
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002232 return true;
2233}
2234
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002235int totalRegisterCount(const sh::Uniform &uniform)
2236{
2237 int registerCount = 0;
2238
2239 if (!uniform.fields.empty())
2240 {
2241 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2242 {
2243 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2244 }
2245 }
2246 else
2247 {
2248 registerCount = 1;
2249 }
2250
2251 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2252}
2253
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002254bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002255{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002256 if (!constant.fields.empty())
2257 {
2258 if (constant.arraySize > 0)
2259 {
2260 unsigned int elementRegisterIndex = constant.registerIndex;
2261
2262 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2263 {
2264 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2265 {
2266 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002267 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madill010fffa2013-06-20 11:55:53 -04002268 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002269 if (!defineUniform(shader, fieldUniform, infoLog))
2270 {
2271 return false;
2272 }
2273 elementRegisterIndex += totalRegisterCount(field);
2274 }
2275 }
2276 }
2277 else
2278 {
2279 unsigned int fieldRegisterIndex = constant.registerIndex;
2280
2281 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2282 {
2283 const sh::Uniform &field = constant.fields[fieldIndex];
2284 const std::string &uniformName = constant.name + "." + field.name;
2285
Jamie Madill010fffa2013-06-20 11:55:53 -04002286 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002287 fieldUniform.fields = field.fields;
2288
2289 if (!defineUniform(shader, fieldUniform, infoLog))
2290 {
2291 return false;
2292 }
2293 fieldRegisterIndex += totalRegisterCount(field);
2294 }
2295 }
2296
2297 return true;
2298 }
2299
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002300 if (constant.type == GL_SAMPLER_2D ||
2301 constant.type == GL_SAMPLER_CUBE)
2302 {
2303 unsigned int samplerIndex = constant.registerIndex;
2304
2305 do
2306 {
2307 if (shader == GL_VERTEX_SHADER)
2308 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002309 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002310 {
2311 mSamplersVS[samplerIndex].active = true;
2312 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2313 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2314 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2315 }
2316 else
2317 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002318 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002319 return false;
2320 }
2321 }
2322 else if (shader == GL_FRAGMENT_SHADER)
2323 {
2324 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2325 {
2326 mSamplersPS[samplerIndex].active = true;
2327 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2328 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2329 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2330 }
2331 else
2332 {
2333 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2334 return false;
2335 }
2336 }
2337 else UNREACHABLE();
2338
2339 samplerIndex++;
2340 }
2341 while (samplerIndex < constant.registerIndex + constant.arraySize);
2342 }
2343
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002344 Uniform *uniform = NULL;
2345 GLint location = getUniformLocation(constant.name);
2346
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002347 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002348 {
2349 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002350 }
2351 else
2352 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002353 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002354 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002355
2356 if (!uniform)
2357 {
2358 return false;
2359 }
2360
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002361 if (shader == GL_FRAGMENT_SHADER)
2362 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002363 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002364 }
2365 else if (shader == GL_VERTEX_SHADER)
2366 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002367 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002368 }
2369 else UNREACHABLE();
2370
2371 if (location >= 0)
2372 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002373 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002374 }
2375
2376 mUniforms.push_back(uniform);
2377 unsigned int uniformIndex = mUniforms.size() - 1;
2378
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002379 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002380 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002381 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002382 }
2383
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002384 if (shader == GL_VERTEX_SHADER)
2385 {
2386 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2387 {
2388 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2389 return false;
2390 }
2391 }
2392 else if (shader == GL_FRAGMENT_SHADER)
2393 {
2394 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2395 {
2396 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2397 return false;
2398 }
2399 }
2400 else UNREACHABLE();
2401
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002402 return true;
2403}
2404
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002405bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2406{
2407 const char* blockName = vertexInterfaceBlock.name.c_str();
2408
2409 // validate blocks for the same member types
2410 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2411 {
2412 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2413 return false;
2414 }
2415
2416 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2417 {
2418 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2419 return false;
2420 }
2421
2422 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2423 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2424 {
2425 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2426 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2427
2428 if (vertexMember.name != fragmentMember.name)
2429 {
2430 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2431 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2432 return false;
2433 }
2434
2435 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2436 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2437 {
2438 return false;
2439 }
2440 }
2441
2442 return true;
2443}
2444
2445bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2446{
2447 // Check that interface blocks defined in the vertex and fragment shaders are identical
2448 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2449 UniformBlockMap linkedUniformBlocks;
2450
2451 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2452 {
2453 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2454 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2455 }
2456
2457 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2458 {
2459 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2460 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2461 if (entry != linkedUniformBlocks.end())
2462 {
2463 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2464 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2465 {
2466 return false;
2467 }
2468 }
2469 }
2470
2471 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2472 {
2473 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2474 {
2475 return false;
2476 }
2477 }
2478
2479 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2480 {
2481 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2482 {
2483 return false;
2484 }
2485 }
2486
2487 return true;
2488}
2489
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002490void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2491{
2492 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2493 {
2494 const sh::Uniform &uniform = uniforms[uniformIndex];
Jamie Madillacdd70f2013-06-07 14:39:56 -04002495 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002496
2497 if (!uniform.fields.empty())
2498 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002499 if (uniform.arraySize > 0)
2500 {
2501 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2502 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002503 const std::string uniformElementName = uniformName + arrayString(arrayElement);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002504 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2505 }
2506 }
2507 else
2508 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002509 defineUniformBlockMembers(uniform.fields, uniformName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002510 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002511 }
2512 else
2513 {
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002514 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2515 blockIndex, **blockInfoItr);
2516
2517 // add to uniform list, but not index, since uniform block uniforms have no location
2518 blockUniformIndexes->push_back(mUniforms.size());
2519 mUniforms.push_back(newUniform);
2520 (*blockInfoItr)++;
2521 }
2522 }
2523}
2524
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002525bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2526{
2527 // create uniform block entries if they do not exist
2528 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2529 {
2530 std::vector<unsigned int> blockUniformIndexes;
2531 const unsigned int blockIndex = mUniformBlocks.size();
2532
2533 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002534 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2535 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002536
2537 // create all the uniform blocks
2538 if (interfaceBlock.arraySize > 0)
2539 {
2540 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2541 {
2542 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2543 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2544 mUniformBlocks.push_back(newUniformBlock);
2545 }
2546 }
2547 else
2548 {
2549 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2550 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2551 mUniformBlocks.push_back(newUniformBlock);
2552 }
2553 }
2554
2555 // Assign registers to the uniform blocks
2556 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2557 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2558 ASSERT(blockIndex != GL_INVALID_INDEX);
2559 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2560
2561 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2562 {
2563 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2564 ASSERT(uniformBlock->name == interfaceBlock.name);
2565
2566 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2567 {
2568 return false;
2569 }
2570 }
2571
2572 return true;
2573}
2574
2575bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2576{
2577 if (shader == GL_VERTEX_SHADER)
2578 {
2579 uniformBlock->vsRegisterIndex = registerIndex;
2580 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2581
2582 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2583 {
2584 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2585 return false;
2586 }
2587 }
2588 else if (shader == GL_FRAGMENT_SHADER)
2589 {
2590 uniformBlock->psRegisterIndex = registerIndex;
2591 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2592
2593 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2594 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002595 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002596 return false;
2597 }
2598 }
2599 else UNREACHABLE();
2600
2601 return true;
2602}
2603
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002604std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2605{
2606 // for now we only handle point sprite emulation
2607 ASSERT(usesPointSpriteEmulation());
2608 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2609}
2610
2611std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2612{
2613 ASSERT(registers >= 0);
2614 ASSERT(vertexShader->mUsesPointSize);
2615 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2616
2617 std::string geomHLSL;
2618
2619 std::string varyingSemantic = "TEXCOORD";
2620
2621 std::string fragCoordSemantic;
2622 std::string pointCoordSemantic;
2623
2624 int reservedRegisterIndex = registers;
2625
2626 if (fragmentShader->mUsesFragCoord)
2627 {
2628 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2629 }
2630
2631 if (fragmentShader->mUsesPointCoord)
2632 {
2633 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2634 }
2635
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002636 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2637 "\n"
2638 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002639 "{\n";
2640
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002641 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002642
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002643 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002644
2645 if (fragmentShader->mUsesFragCoord)
2646 {
2647 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2648 }
2649
2650 geomHLSL += " float gl_PointSize : PSIZE;\n"
2651 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002652 "};\n"
2653 "\n"
2654 "struct GS_OUTPUT\n"
2655 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002656
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002657 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002658
2659 if (fragmentShader->mUsesFragCoord)
2660 {
2661 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2662 }
2663
2664 if (fragmentShader->mUsesPointCoord)
2665 {
2666 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2667 }
2668
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002669 geomHLSL += " float gl_PointSize : PSIZE;\n"
2670 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002671 "};\n"
2672 "\n"
2673 "static float2 pointSpriteCorners[] = \n"
2674 "{\n"
2675 " float2( 0.5f, -0.5f),\n"
2676 " float2( 0.5f, 0.5f),\n"
2677 " float2(-0.5f, -0.5f),\n"
2678 " float2(-0.5f, 0.5f)\n"
2679 "};\n"
2680 "\n"
2681 "static float2 pointSpriteTexcoords[] = \n"
2682 "{\n"
2683 " float2(1.0f, 1.0f),\n"
2684 " float2(1.0f, 0.0f),\n"
2685 " float2(0.0f, 1.0f),\n"
2686 " float2(0.0f, 0.0f)\n"
2687 "};\n"
2688 "\n"
2689 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2690 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2691 "\n"
2692 "[maxvertexcount(4)]\n"
2693 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2694 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002695 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2696 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002697
2698 for (int r = 0; r < registers; r++)
2699 {
2700 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2701 }
2702
2703 if (fragmentShader->mUsesFragCoord)
2704 {
2705 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2706 }
2707
2708 geomHLSL += " \n"
2709 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2710 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002711 " 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 +00002712
2713 for (int corner = 0; corner < 4; corner++)
2714 {
2715 geomHLSL += " \n"
2716 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2717
2718 if (fragmentShader->mUsesPointCoord)
2719 {
2720 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2721 }
2722
2723 geomHLSL += " outStream.Append(output);\n";
2724 }
2725
2726 geomHLSL += " \n"
2727 " outStream.RestartStrip();\n"
2728 "}\n";
2729
2730 return geomHLSL;
2731}
2732
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002733// This method needs to match OutputHLSL::decorate
2734std::string ProgramBinary::decorateAttribute(const std::string &name)
2735{
2736 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2737 {
2738 return "_" + name;
2739 }
2740
2741 return name;
2742}
2743
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002744bool ProgramBinary::isValidated() const
2745{
2746 return mValidated;
2747}
2748
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002749void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002750{
2751 // Skip over inactive attributes
2752 unsigned int activeAttribute = 0;
2753 unsigned int attribute;
2754 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2755 {
2756 if (mLinkedAttribute[attribute].name.empty())
2757 {
2758 continue;
2759 }
2760
2761 if (activeAttribute == index)
2762 {
2763 break;
2764 }
2765
2766 activeAttribute++;
2767 }
2768
2769 if (bufsize > 0)
2770 {
2771 const char *string = mLinkedAttribute[attribute].name.c_str();
2772
2773 strncpy(name, string, bufsize);
2774 name[bufsize - 1] = '\0';
2775
2776 if (length)
2777 {
2778 *length = strlen(name);
2779 }
2780 }
2781
2782 *size = 1; // Always a single 'type' instance
2783
2784 *type = mLinkedAttribute[attribute].type;
2785}
2786
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002787GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002788{
2789 int count = 0;
2790
2791 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2792 {
2793 if (!mLinkedAttribute[attributeIndex].name.empty())
2794 {
2795 count++;
2796 }
2797 }
2798
2799 return count;
2800}
2801
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002802GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002803{
2804 int maxLength = 0;
2805
2806 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2807 {
2808 if (!mLinkedAttribute[attributeIndex].name.empty())
2809 {
2810 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2811 }
2812 }
2813
2814 return maxLength;
2815}
2816
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002817void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002818{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002819 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002820
2821 if (bufsize > 0)
2822 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002823 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002824
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002825 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002826 {
2827 string += "[0]";
2828 }
2829
2830 strncpy(name, string.c_str(), bufsize);
2831 name[bufsize - 1] = '\0';
2832
2833 if (length)
2834 {
2835 *length = strlen(name);
2836 }
2837 }
2838
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002839 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002840
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002841 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002842}
2843
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002844GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002845{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002846 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002847}
2848
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002849GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002850{
2851 int maxLength = 0;
2852
2853 unsigned int numUniforms = mUniforms.size();
2854 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2855 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002856 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002857 {
2858 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2859 if (mUniforms[uniformIndex]->isArray())
2860 {
2861 length += 3; // Counting in "[0]".
2862 }
2863 maxLength = std::max(length, maxLength);
2864 }
2865 }
2866
2867 return maxLength;
2868}
2869
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002870GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2871{
2872 const gl::Uniform& uniform = *mUniforms[index];
2873
2874 switch (pname)
2875 {
2876 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2877 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002878 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 +00002879 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002880
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002881 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2882 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2883 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2884 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002885
2886 default:
2887 UNREACHABLE();
2888 break;
2889 }
2890 return 0;
2891}
2892
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002893void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2894{
2895 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2896
2897 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2898
2899 if (bufSize > 0)
2900 {
2901 std::string string = uniformBlock.name;
2902
2903 if (uniformBlock.isArrayElement())
2904 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002905 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002906 }
2907
2908 strncpy(uniformBlockName, string.c_str(), bufSize);
2909 uniformBlockName[bufSize - 1] = '\0';
2910
2911 if (length)
2912 {
2913 *length = strlen(uniformBlockName);
2914 }
2915 }
2916}
2917
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002918void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2919{
2920 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2921
2922 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2923
2924 switch (pname)
2925 {
2926 case GL_UNIFORM_BLOCK_DATA_SIZE:
2927 *params = static_cast<GLint>(uniformBlock.dataSize);
2928 break;
2929 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002930 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002931 break;
2932 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2933 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2934 break;
2935 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2936 {
2937 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2938 {
2939 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2940 }
2941 }
2942 break;
2943 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2944 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2945 break;
2946 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2947 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2948 break;
2949 default: UNREACHABLE();
2950 }
2951}
2952
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002953GLuint ProgramBinary::getActiveUniformBlockCount() const
2954{
2955 return mUniformBlocks.size();
2956}
2957
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002958GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2959{
2960 unsigned int maxLength = 0;
2961
2962 unsigned int numUniformBlocks = mUniformBlocks.size();
2963 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2964 {
2965 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2966 if (!uniformBlock.name.empty())
2967 {
2968 const unsigned int length = uniformBlock.name.length() + 1;
2969
2970 // Counting in "[0]".
2971 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2972
2973 maxLength = std::max(length + arrayLength, maxLength);
2974 }
2975 }
2976
2977 return maxLength;
2978}
2979
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002980void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002981{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002982 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002983 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002984 {
2985 mValidated = false;
2986 }
2987 else
2988 {
2989 mValidated = true;
2990 }
2991}
2992
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002993bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002994{
2995 // if any two active samplers in a program are of different types, but refer to the same
2996 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2997 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2998
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002999 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003000 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003001
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003002 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003003 {
3004 textureUnitType[i] = TEXTURE_UNKNOWN;
3005 }
3006
3007 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3008 {
3009 if (mSamplersPS[i].active)
3010 {
3011 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3012
3013 if (unit >= maxCombinedTextureImageUnits)
3014 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003015 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003016 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003017 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003018 }
3019
3020 return false;
3021 }
3022
3023 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3024 {
3025 if (mSamplersPS[i].textureType != textureUnitType[unit])
3026 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003027 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003028 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003029 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003030 }
3031
3032 return false;
3033 }
3034 }
3035 else
3036 {
3037 textureUnitType[unit] = mSamplersPS[i].textureType;
3038 }
3039 }
3040 }
3041
3042 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3043 {
3044 if (mSamplersVS[i].active)
3045 {
3046 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3047
3048 if (unit >= maxCombinedTextureImageUnits)
3049 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003050 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003051 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003052 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003053 }
3054
3055 return false;
3056 }
3057
3058 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3059 {
3060 if (mSamplersVS[i].textureType != textureUnitType[unit])
3061 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003062 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003063 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003064 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003065 }
3066
3067 return false;
3068 }
3069 }
3070 else
3071 {
3072 textureUnitType[unit] = mSamplersVS[i].textureType;
3073 }
3074 }
3075 }
3076
3077 return true;
3078}
3079
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003080ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3081{
3082}
3083
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003084struct AttributeSorter
3085{
3086 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3087 : originalIndices(semanticIndices)
3088 {
3089 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3090 {
3091 indices[i] = i;
3092 }
3093
3094 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3095 }
3096
3097 bool operator()(int a, int b)
3098 {
3099 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3100 }
3101
3102 int indices[MAX_VERTEX_ATTRIBS];
3103 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3104};
3105
3106void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3107{
3108 AttributeSorter sorter(mSemanticIndex);
3109
3110 int oldIndices[MAX_VERTEX_ATTRIBS];
3111 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3112
3113 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3114 {
3115 oldIndices[i] = mSemanticIndex[i];
3116 oldTranslatedAttributes[i] = attributes[i];
3117 }
3118
3119 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3120 {
3121 int oldIndex = sorter.indices[i];
3122 sortedSemanticIndices[i] = oldIndices[oldIndex];
3123 attributes[i] = oldTranslatedAttributes[oldIndex];
3124 }
3125}
3126
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003127}