blob: a23fb543e00bab204662dba8ba523ba65f13120b [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000039namespace gl_d3d
40{
41 std::string TypeString(GLenum type)
42 {
43 switch (type)
44 {
45 case GL_FLOAT: return "float";
46 case GL_FLOAT_VEC2: return "float2";
47 case GL_FLOAT_VEC3: return "float3";
48 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000049 case GL_INT: return "int";
50 case GL_INT_VEC2: return "int2";
51 case GL_INT_VEC3: return "int3";
52 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000053 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000054 case GL_UNSIGNED_INT_VEC2: return "uint2";
55 case GL_UNSIGNED_INT_VEC3: return "uint3";
56 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000057 case GL_FLOAT_MAT2: return "float2x2";
58 case GL_FLOAT_MAT3: return "float3x3";
59 case GL_FLOAT_MAT4: return "float4x4";
60 case GL_FLOAT_MAT2x3: return "float2x3";
61 case GL_FLOAT_MAT3x2: return "float3x2";
62 case GL_FLOAT_MAT2x4: return "float2x4";
63 case GL_FLOAT_MAT4x2: return "float4x2";
64 case GL_FLOAT_MAT3x4: return "float3x4";
65 case GL_FLOAT_MAT4x3: return "float4x3";
66 default: UNREACHABLE(); return "invalid-gl-type";
67 }
68 }
69}
70
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000071namespace
72{
73
74unsigned int parseAndStripArrayIndex(std::string* name)
75{
76 unsigned int subscript = GL_INVALID_INDEX;
77
78 // Strip any trailing array operator and retrieve the subscript
79 size_t open = name->find_last_of('[');
80 size_t close = name->find_last_of(']');
81 if (open != std::string::npos && close == name->length() - 1)
82 {
83 subscript = atoi(name->substr(open + 1).c_str());
84 name->erase(open);
85 }
86
87 return subscript;
88}
89
90}
91
daniel@transgaming.comdb019952012-12-20 21:13:32 +000092UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
93 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000094{
95}
96
daniel@transgaming.come87ca002012-07-24 18:30:43 +000097unsigned int ProgramBinary::mCurrentSerial = 1;
98
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000099ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000100{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101 mPixelExecutable = NULL;
102 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000103 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000104
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000105 mValidated = false;
106
107 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
108 {
109 mSemanticIndex[index] = -1;
110 }
111
112 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
113 {
114 mSamplersPS[index].active = false;
115 }
116
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000117 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118 {
119 mSamplersVS[index].active = false;
120 }
121
122 mUsedVertexSamplerRange = 0;
123 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000124 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000125 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000126}
127
128ProgramBinary::~ProgramBinary()
129{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000130 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000131 mPixelExecutable = NULL;
132
daniel@transgaming.com95892412012-11-28 20:59:09 +0000133 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000134 mVertexExecutable = NULL;
135
136 delete mGeometryExecutable;
137 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000138
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000139 while (!mUniforms.empty())
140 {
141 delete mUniforms.back();
142 mUniforms.pop_back();
143 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000144
145 while (!mUniformBlocks.empty())
146 {
147 delete mUniformBlocks.back();
148 mUniformBlocks.pop_back();
149 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000150}
151
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000152unsigned int ProgramBinary::getSerial() const
153{
154 return mSerial;
155}
156
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000157int ProgramBinary::getShaderVersion() const
158{
159 return mShaderVersion;
160}
161
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000162unsigned int ProgramBinary::issueSerial()
163{
164 return mCurrentSerial++;
165}
166
daniel@transgaming.com95892412012-11-28 20:59:09 +0000167rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000168{
169 return mPixelExecutable;
170}
171
daniel@transgaming.com95892412012-11-28 20:59:09 +0000172rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000173{
174 return mVertexExecutable;
175}
176
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000177rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
178{
179 return mGeometryExecutable;
180}
181
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000182GLuint ProgramBinary::getAttributeLocation(const char *name)
183{
184 if (name)
185 {
186 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
187 {
188 if (mLinkedAttribute[index].name == std::string(name))
189 {
190 return index;
191 }
192 }
193 }
194
195 return -1;
196}
197
198int ProgramBinary::getSemanticIndex(int attributeIndex)
199{
200 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
201
202 return mSemanticIndex[attributeIndex];
203}
204
205// Returns one more than the highest sampler index used.
206GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
207{
208 switch (type)
209 {
210 case SAMPLER_PIXEL:
211 return mUsedPixelSamplerRange;
212 case SAMPLER_VERTEX:
213 return mUsedVertexSamplerRange;
214 default:
215 UNREACHABLE();
216 return 0;
217 }
218}
219
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000220bool ProgramBinary::usesPointSize() const
221{
222 return mUsesPointSize;
223}
224
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000225bool ProgramBinary::usesPointSpriteEmulation() const
226{
227 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
228}
229
230bool ProgramBinary::usesGeometryShader() const
231{
232 return usesPointSpriteEmulation();
233}
234
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000235// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
236// index (0-15 for the pixel shader and 0-3 for the vertex shader).
237GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
238{
239 GLint logicalTextureUnit = -1;
240
241 switch (type)
242 {
243 case SAMPLER_PIXEL:
244 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
245
246 if (mSamplersPS[samplerIndex].active)
247 {
248 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
249 }
250 break;
251 case SAMPLER_VERTEX:
252 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
253
254 if (mSamplersVS[samplerIndex].active)
255 {
256 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
257 }
258 break;
259 default: UNREACHABLE();
260 }
261
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000262 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000263 {
264 return logicalTextureUnit;
265 }
266
267 return -1;
268}
269
270// Returns the texture type for a given Direct3D 9 sampler type and
271// index (0-15 for the pixel shader and 0-3 for the vertex shader).
272TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
273{
274 switch (type)
275 {
276 case SAMPLER_PIXEL:
277 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
278 ASSERT(mSamplersPS[samplerIndex].active);
279 return mSamplersPS[samplerIndex].textureType;
280 case SAMPLER_VERTEX:
281 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
282 ASSERT(mSamplersVS[samplerIndex].active);
283 return mSamplersVS[samplerIndex].textureType;
284 default: UNREACHABLE();
285 }
286
287 return TEXTURE_2D;
288}
289
290GLint ProgramBinary::getUniformLocation(std::string name)
291{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000292 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000293
294 unsigned int numUniforms = mUniformIndex.size();
295 for (unsigned int location = 0; location < numUniforms; location++)
296 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000297 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000298 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000299 const int index = mUniformIndex[location].index;
300 const bool isArray = mUniforms[index]->isArray();
301
302 if ((isArray && mUniformIndex[location].element == subscript) ||
303 (subscript == GL_INVALID_INDEX))
304 {
305 return location;
306 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000307 }
308 }
309
310 return -1;
311}
312
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000313GLuint ProgramBinary::getUniformIndex(std::string name)
314{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000315 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000316
317 // The app is not allowed to specify array indices other than 0 for arrays of basic types
318 if (subscript != 0 && subscript != GL_INVALID_INDEX)
319 {
320 return GL_INVALID_INDEX;
321 }
322
323 unsigned int numUniforms = mUniforms.size();
324 for (unsigned int index = 0; index < numUniforms; index++)
325 {
326 if (mUniforms[index]->name == name)
327 {
328 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
329 {
330 return index;
331 }
332 }
333 }
334
335 return GL_INVALID_INDEX;
336}
337
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000338GLuint ProgramBinary::getUniformBlockIndex(std::string name)
339{
340 unsigned int subscript = parseAndStripArrayIndex(&name);
341
342 unsigned int numUniformBlocks = mUniformBlocks.size();
343 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
344 {
345 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
346 if (uniformBlock.name == name)
347 {
348 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
349 if (subscript == uniformBlock.elementIndex || arrayElementZero)
350 {
351 return blockIndex;
352 }
353 }
354 }
355
356 return GL_INVALID_INDEX;
357}
358
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000359UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
360{
361 ASSERT(blockIndex < mUniformBlocks.size());
362 return mUniformBlocks[blockIndex];
363}
364
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000365template <typename T>
366bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000367{
368 if (location < 0 || location >= (int)mUniformIndex.size())
369 {
370 return false;
371 }
372
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000373 const int components = UniformComponentCount(targetUniformType);
374 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
375
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000376 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
377 targetUniform->dirty = true;
378
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000379 int elementCount = targetUniform->elementCount();
380
381 if (elementCount == 1 && count > 1)
382 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
383
384 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
385
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000386 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000387 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000388 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000389
390 for (int i = 0; i < count; i++)
391 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000392 for (int c = 0; c < components; c++)
393 {
394 target[c] = v[c];
395 }
396 for (int c = components; c < 4; c++)
397 {
398 target[c] = 0;
399 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000400 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000401 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000402 }
403 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000404 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000406 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000407
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000408 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000409 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000410 for (int c = 0; c < components; c++)
411 {
412 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
413 }
414 for (int c = components; c < 4; c++)
415 {
416 boolParams[c] = GL_FALSE;
417 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000418 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000419 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000420 }
421 }
422 else
423 {
424 return false;
425 }
426
427 return true;
428}
429
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000430bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
431{
432 return setUniform(location, count, v, GL_FLOAT);
433}
434
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
436{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000437 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438}
439
440bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
441{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000442 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000443}
444
445bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
446{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000447 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448}
449
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000450template<typename T>
451void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000453 int copyWidth = std::min(targetHeight, srcWidth);
454 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000455
456 for (int x = 0; x < copyWidth; x++)
457 {
458 for (int y = 0; y < copyHeight; y++)
459 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000460 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000461 }
462 }
463 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000464 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000466 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000467 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000468 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000469 }
470 }
471 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000472 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000473 {
474 for (int x = 0; x < targetWidth; x++)
475 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000476 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000477 }
478 }
479}
480
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000481template<typename T>
482void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
483{
484 int copyWidth = std::min(targetWidth, srcWidth);
485 int copyHeight = std::min(targetHeight, srcHeight);
486
487 for (int y = 0; y < copyHeight; y++)
488 {
489 for (int x = 0; x < copyWidth; x++)
490 {
491 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
492 }
493 }
494 // clear unfilled right side
495 for (int y = 0; y < copyHeight; y++)
496 {
497 for (int x = copyWidth; x < targetWidth; x++)
498 {
499 target[y * targetWidth + x] = static_cast<T>(0);
500 }
501 }
502 // clear unfilled bottom.
503 for (int y = copyHeight; y < targetHeight; y++)
504 {
505 for (int x = 0; x < targetWidth; x++)
506 {
507 target[y * targetWidth + x] = static_cast<T>(0);
508 }
509 }
510}
511
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000512template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000513bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000514{
515 if (location < 0 || location >= (int)mUniformIndex.size())
516 {
517 return false;
518 }
519
520 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
521 targetUniform->dirty = true;
522
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000523 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524 {
525 return false;
526 }
527
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000528 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000530 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000531 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
532
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000533 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000534 const unsigned int targetMatrixStride = (4 * rows);
535 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000536
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000537 for (int i = 0; i < count; i++)
538 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000539 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
540 if (transpose == GL_FALSE)
541 {
542 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
543 }
544 else
545 {
546 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
547 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000548 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000549 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000550 }
551
552 return true;
553}
554
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000555bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000556{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000557 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000558}
559
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000560bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000561{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000562 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000563}
564
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000565bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000566{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568}
569
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000570bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000571{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000572 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000573}
574
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000575bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000576{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000577 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000578}
579
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000580bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000581{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000582 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000583}
584
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000585bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000586{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000587 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000588}
589
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000590bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000591{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000592 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000593}
594
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000595bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000596{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000597 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000598}
599
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
601{
602 if (location < 0 || location >= (int)mUniformIndex.size())
603 {
604 return false;
605 }
606
607 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
608 targetUniform->dirty = true;
609
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000610 int elementCount = targetUniform->elementCount();
611
612 if (elementCount == 1 && count > 1)
613 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
614
615 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
616
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000617 if (targetUniform->type == GL_INT ||
618 targetUniform->type == GL_SAMPLER_2D ||
619 targetUniform->type == GL_SAMPLER_CUBE)
620 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000621 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000622
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000623 for (int i = 0; i < count; i++)
624 {
625 target[0] = v[0];
626 target[1] = 0;
627 target[2] = 0;
628 target[3] = 0;
629 target += 4;
630 v += 1;
631 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000632 }
633 else if (targetUniform->type == GL_BOOL)
634 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000635 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000636
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000637 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000638 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000639 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
640 boolParams[1] = GL_FALSE;
641 boolParams[2] = GL_FALSE;
642 boolParams[3] = GL_FALSE;
643 boolParams += 4;
644 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000645 }
646 }
647 else
648 {
649 return false;
650 }
651
652 return true;
653}
654
655bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
656{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000657 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000658}
659
660bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
661{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000662 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000663}
664
665bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
666{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000667 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668}
669
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000670bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
671{
672 return setUniform(location, count, v, GL_UNSIGNED_INT);
673}
674
675bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
676{
677 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
678}
679
680bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
681{
682 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
683}
684
685bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
686{
687 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
688}
689
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000690template <typename T>
691bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692{
693 if (location < 0 || location >= (int)mUniformIndex.size())
694 {
695 return false;
696 }
697
698 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
699
700 // sized queries -- ensure the provided buffer is large enough
701 if (bufSize)
702 {
703 int requiredBytes = UniformExternalSize(targetUniform->type);
704 if (*bufSize < requiredBytes)
705 {
706 return false;
707 }
708 }
709
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000710 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000711 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000712 const int rows = VariableRowCount(targetUniform->type);
713 const int cols = VariableColumnCount(targetUniform->type);
714 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
715 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000716 else if (uniformType == UniformComponentType(targetUniform->type))
717 {
718 unsigned int size = UniformComponentCount(targetUniform->type);
719 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
720 size * sizeof(T));
721 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000722 else
723 {
724 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000725 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000727 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000728 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000729 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000730
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000731 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000732 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000733 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000734 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000735 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000736 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000737
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000738 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000739 {
740 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
741
742 for (unsigned int i = 0; i < size; i++)
743 {
744 params[i] = static_cast<T>(floatParams[i]);
745 }
746 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000747 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000748
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000749 case GL_INT:
750 {
751 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
752
753 for (unsigned int i = 0; i < size; i++)
754 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000755 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000756 }
757 }
758 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000759
760 case GL_UNSIGNED_INT:
761 {
762 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000763
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000764 for (unsigned int i = 0; i < size; i++)
765 {
766 params[i] = static_cast<T>(uintParams[i]);
767 }
768 }
769 break;
770
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000771 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000772 }
773 }
774
775 return true;
776}
777
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000778bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
779{
780 return getUniformv(location, bufSize, params, GL_FLOAT);
781}
782
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000783bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
784{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000785 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000786}
787
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000788bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
789{
790 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
791}
792
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000793void ProgramBinary::dirtyAllUniforms()
794{
795 unsigned int numUniforms = mUniforms.size();
796 for (unsigned int index = 0; index < numUniforms; index++)
797 {
798 mUniforms[index]->dirty = true;
799 }
800}
801
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000802// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000803void ProgramBinary::applyUniforms()
804{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000805 // Retrieve sampler uniform values
806 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
807 {
808 Uniform *targetUniform = *ub;
809
810 if (targetUniform->dirty)
811 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000812 if (targetUniform->type == GL_SAMPLER_2D ||
813 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000814 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000815 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000816 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000817
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000818 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000819 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000820 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000821
822 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000823 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000824 unsigned int samplerIndex = firstIndex + i;
825
826 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000827 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000828 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000829 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000830 }
831 }
832 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000833
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000834 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000835 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000836 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000837
838 for (int i = 0; i < count; i++)
839 {
840 unsigned int samplerIndex = firstIndex + i;
841
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000842 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000843 {
844 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000845 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000846 }
847 }
848 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000849 }
850 }
851 }
852
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000853 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000854}
855
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000856bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
857{
858 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
859 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
860
861 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
862 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
863
864 ASSERT(boundBuffers.size() == mUniformBlocks.size());
865
866 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
867 {
868 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
869 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
870
871 ASSERT(uniformBlock && uniformBuffer);
872
873 if (uniformBuffer->size() < uniformBlock->dataSize)
874 {
875 // undefined behaviour
876 return false;
877 }
878
879 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
880
881 if (uniformBlock->isReferencedByVertexShader())
882 {
883 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
884 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
885 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
886 vertexUniformBuffers[registerIndex] = uniformBuffer;
887 }
888
889 if (uniformBlock->isReferencedByFragmentShader())
890 {
891 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
892 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
893 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
894 fragmentUniformBuffers[registerIndex] = uniformBuffer;
895 }
896 }
897
898 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
899}
900
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000901// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
902// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000903int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000904{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000905 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000906
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000907 fragmentShader->resetVaryingsRegisterAssignment();
908
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000909 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
910 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000911 GLenum transposedType = TransposeMatrixType(varying->type);
912 int n = VariableRowCount(transposedType) * varying->size;
913 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000914 bool success = false;
915
916 if (m == 2 || m == 3 || m == 4)
917 {
918 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
919 {
920 bool available = true;
921
922 for (int y = 0; y < n && available; y++)
923 {
924 for (int x = 0; x < m && available; x++)
925 {
926 if (packing[r + y][x])
927 {
928 available = false;
929 }
930 }
931 }
932
933 if (available)
934 {
935 varying->reg = r;
936 varying->col = 0;
937
938 for (int y = 0; y < n; y++)
939 {
940 for (int x = 0; x < m; x++)
941 {
942 packing[r + y][x] = &*varying;
943 }
944 }
945
946 success = true;
947 }
948 }
949
950 if (!success && m == 2)
951 {
952 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
953 {
954 bool available = true;
955
956 for (int y = 0; y < n && available; y++)
957 {
958 for (int x = 2; x < 4 && available; x++)
959 {
960 if (packing[r + y][x])
961 {
962 available = false;
963 }
964 }
965 }
966
967 if (available)
968 {
969 varying->reg = r;
970 varying->col = 2;
971
972 for (int y = 0; y < n; y++)
973 {
974 for (int x = 2; x < 4; x++)
975 {
976 packing[r + y][x] = &*varying;
977 }
978 }
979
980 success = true;
981 }
982 }
983 }
984 }
985 else if (m == 1)
986 {
987 int space[4] = {0};
988
989 for (int y = 0; y < maxVaryingVectors; y++)
990 {
991 for (int x = 0; x < 4; x++)
992 {
993 space[x] += packing[y][x] ? 0 : 1;
994 }
995 }
996
997 int column = 0;
998
999 for (int x = 0; x < 4; x++)
1000 {
1001 if (space[x] >= n && space[x] < space[column])
1002 {
1003 column = x;
1004 }
1005 }
1006
1007 if (space[column] >= n)
1008 {
1009 for (int r = 0; r < maxVaryingVectors; r++)
1010 {
1011 if (!packing[r][column])
1012 {
1013 varying->reg = r;
1014
1015 for (int y = r; y < r + n; y++)
1016 {
1017 packing[y][column] = &*varying;
1018 }
1019
1020 break;
1021 }
1022 }
1023
1024 varying->col = column;
1025
1026 success = true;
1027 }
1028 }
1029 else UNREACHABLE();
1030
1031 if (!success)
1032 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001033 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001034
1035 return -1;
1036 }
1037 }
1038
1039 // Return the number of used registers
1040 int registers = 0;
1041
1042 for (int r = 0; r < maxVaryingVectors; r++)
1043 {
1044 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1045 {
1046 registers++;
1047 }
1048 }
1049
1050 return registers;
1051}
1052
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001053bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1054 std::string& pixelHLSL, std::string& vertexHLSL,
1055 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001056{
1057 if (pixelHLSL.empty() || vertexHLSL.empty())
1058 {
1059 return false;
1060 }
1061
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001062 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1063 bool usesFragColor = fragmentShader->mUsesFragColor;
1064 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001065 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001066 {
1067 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1068 return false;
1069 }
1070
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001071 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001072 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001073 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001074
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001075 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1076
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001077 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1078 // - with a 3.0 context, the output color is copied to channel 0
1079 // - with a 2.0 context, the output color is broadcast to all channels
1080 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1081 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1082
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001083 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001084 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001085 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001086
1087 return false;
1088 }
1089
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001090 vertexShader->resetVaryingsRegisterAssignment();
1091
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001092 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1093 {
1094 bool matched = false;
1095
1096 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1097 {
1098 if (output->name == input->name)
1099 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001100 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001101 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001102 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 +00001103
1104 return false;
1105 }
1106
1107 output->reg = input->reg;
1108 output->col = input->col;
1109
1110 matched = true;
1111 break;
1112 }
1113 }
1114
1115 if (!matched)
1116 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001117 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001118
1119 return false;
1120 }
1121 }
1122
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001123 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001124 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001125 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001126 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1127
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001128 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1129
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001130 // special varyings that use reserved registers
1131 int reservedRegisterIndex = registers;
1132 std::string fragCoordSemantic;
1133 std::string pointCoordSemantic;
1134
1135 if (fragmentShader->mUsesFragCoord)
1136 {
1137 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1138 }
1139
1140 if (fragmentShader->mUsesPointCoord)
1141 {
1142 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1143 // In DX11 we compute this in the GS.
1144 if (shaderModel == 3)
1145 {
1146 pointCoordSemantic = "TEXCOORD0";
1147 }
1148 else if (shaderModel >= 4)
1149 {
1150 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1151 }
1152 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001153
1154 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001155 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001156
1157 int semanticIndex = 0;
1158 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1159 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001160 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001161 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1162
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001163 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001164 }
1165
1166 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001167 "\n"
1168 "struct VS_OUTPUT\n"
1169 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001170
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001171 if (shaderModel < 4)
1172 {
1173 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1174 }
1175
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001176 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001177
1178 if (fragmentShader->mUsesFragCoord)
1179 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001180 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001181 }
1182
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001183 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001184 {
1185 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1186 }
1187
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001188 if (shaderModel >= 4)
1189 {
1190 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1191 }
1192
1193 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001194 "\n"
1195 "VS_OUTPUT main(VS_INPUT input)\n"
1196 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001197
1198 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1199 {
1200 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1201
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001202 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001203 {
1204 vertexHLSL += "transpose";
1205 }
1206
1207 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1208 }
1209
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001210 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1211 {
1212 vertexHLSL += "\n"
1213 " dx_initConstantBuffers();\n";
1214 }
1215
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001216 if (shaderModel >= 4)
1217 {
1218 vertexHLSL += "\n"
1219 " gl_main();\n"
1220 "\n"
1221 " VS_OUTPUT output;\n"
1222 " output.gl_Position.x = gl_Position.x;\n"
1223 " output.gl_Position.y = -gl_Position.y;\n"
1224 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1225 " output.gl_Position.w = gl_Position.w;\n";
1226 }
1227 else
1228 {
1229 vertexHLSL += "\n"
1230 " gl_main();\n"
1231 "\n"
1232 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001233 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1234 " 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 +00001235 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1236 " output.gl_Position.w = gl_Position.w;\n";
1237 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001238
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001239 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001240 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001241 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242 }
1243
1244 if (fragmentShader->mUsesFragCoord)
1245 {
1246 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1247 }
1248
1249 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1250 {
1251 if (varying->reg >= 0)
1252 {
1253 for (int i = 0; i < varying->size; i++)
1254 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001255 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001256
1257 for (int j = 0; j < rows; j++)
1258 {
1259 int r = varying->reg + i * rows + j;
1260 vertexHLSL += " output.v" + str(r);
1261
1262 bool sharedRegister = false; // Register used by multiple varyings
1263
1264 for (int x = 0; x < 4; x++)
1265 {
1266 if (packing[r][x] && packing[r][x] != packing[r][0])
1267 {
1268 sharedRegister = true;
1269 break;
1270 }
1271 }
1272
1273 if(sharedRegister)
1274 {
1275 vertexHLSL += ".";
1276
1277 for (int x = 0; x < 4; x++)
1278 {
1279 if (packing[r][x] == &*varying)
1280 {
1281 switch(x)
1282 {
1283 case 0: vertexHLSL += "x"; break;
1284 case 1: vertexHLSL += "y"; break;
1285 case 2: vertexHLSL += "z"; break;
1286 case 3: vertexHLSL += "w"; break;
1287 }
1288 }
1289 }
1290 }
1291
1292 vertexHLSL += " = " + varying->name;
1293
1294 if (varying->array)
1295 {
1296 vertexHLSL += "[" + str(i) + "]";
1297 }
1298
1299 if (rows > 1)
1300 {
1301 vertexHLSL += "[" + str(j) + "]";
1302 }
1303
1304 vertexHLSL += ";\n";
1305 }
1306 }
1307 }
1308 }
1309
1310 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001311 " return output;\n"
1312 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001313
1314 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001315 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001316
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001317 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001318
1319 if (fragmentShader->mUsesFragCoord)
1320 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001321 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001322 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001323
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001324 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1325 {
1326 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1327 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001328
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001329 // Must consume the PSIZE element if the geometry shader is not active
1330 // We won't know if we use a GS until we draw
1331 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1332 {
1333 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1334 }
1335
1336 if (fragmentShader->mUsesFragCoord)
1337 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001338 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001339 {
1340 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1341 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001342 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001343 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001344 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1345 }
1346 }
1347
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001348 pixelHLSL += "};\n"
1349 "\n"
1350 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001351 "{\n";
1352
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001353 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001354 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001355 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001356 }
1357
1358 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001359 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001360
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001361 if (fragmentShader->mUsesFrontFacing)
1362 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001363 if (shaderModel >= 4)
1364 {
1365 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1366 "{\n";
1367 }
1368 else
1369 {
1370 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1371 "{\n";
1372 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001373 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001374 else
1375 {
1376 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1377 "{\n";
1378 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001379
1380 if (fragmentShader->mUsesFragCoord)
1381 {
1382 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1383
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001384 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001385 {
1386 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1387 " gl_FragCoord.y = input.dx_VPos.y;\n";
1388 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001389 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001390 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001391 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001392 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001393 }
1394 else
1395 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001396 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1397 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1398 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001399 }
1400
daniel@transgaming.com12985182012-12-20 20:56:31 +00001401 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001402 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001403 }
1404
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001405 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001406 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001407 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1408 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001409 }
1410
1411 if (fragmentShader->mUsesFrontFacing)
1412 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001413 if (shaderModel <= 3)
1414 {
1415 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1416 }
1417 else
1418 {
1419 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1420 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001421 }
1422
1423 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1424 {
1425 if (varying->reg >= 0)
1426 {
1427 for (int i = 0; i < varying->size; i++)
1428 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001429 GLenum transposedType = TransposeMatrixType(varying->type);
1430 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001431 for (int j = 0; j < rows; j++)
1432 {
1433 std::string n = str(varying->reg + i * rows + j);
1434 pixelHLSL += " " + varying->name;
1435
1436 if (varying->array)
1437 {
1438 pixelHLSL += "[" + str(i) + "]";
1439 }
1440
1441 if (rows > 1)
1442 {
1443 pixelHLSL += "[" + str(j) + "]";
1444 }
1445
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001446 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001447 {
1448 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1449 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1450 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1451 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1452 default: UNREACHABLE();
1453 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001454 }
1455 }
1456 }
1457 else UNREACHABLE();
1458 }
1459
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001460 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1461 {
1462 pixelHLSL += "\n"
1463 " dx_initConstantBuffers();\n";
1464 }
1465
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001466 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001467 " gl_main();\n"
1468 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001469 " PS_OUTPUT output;\n";
1470
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001471 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001472 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001473 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001474
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001475 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001476 }
1477
1478 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001479 " return output;\n"
1480 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001481
1482 return true;
1483}
1484
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001485std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1486{
1487 std::string varyingHLSL;
1488
1489 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1490 {
1491 if (varying->reg >= 0)
1492 {
1493 for (int i = 0; i < varying->size; i++)
1494 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001495 GLenum transposedType = TransposeMatrixType(varying->type);
1496 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001497 for (int j = 0; j < rows; j++)
1498 {
1499 switch (varying->interpolation)
1500 {
1501 case Smooth: varyingHLSL += " "; break;
1502 case Flat: varyingHLSL += " nointerpolation "; break;
1503 case Centroid: varyingHLSL += " centroid "; break;
1504 default: UNREACHABLE();
1505 }
1506
1507 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001508 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001509
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001510 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001511 }
1512 }
1513 }
1514 else UNREACHABLE();
1515 }
1516
1517 return varyingHLSL;
1518}
1519
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001520bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1521{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001522 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001523
1524 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001525 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001526 if (format != GL_PROGRAM_BINARY_ANGLE)
1527 {
1528 infoLog.append("Invalid program binary format.");
1529 return false;
1530 }
1531
1532 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001533 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001534 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001535 {
1536 infoLog.append("Invalid program binary version.");
1537 return false;
1538 }
1539
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001540 int compileFlags = 0;
1541 stream.read(&compileFlags);
1542 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1543 {
1544 infoLog.append("Mismatched compilation flags.");
1545 return false;
1546 }
1547
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001548 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1549 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001550 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001552 stream.read(&name);
1553 mLinkedAttribute[i].name = name;
1554 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555 }
1556
1557 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1558 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001559 stream.read(&mSamplersPS[i].active);
1560 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561
1562 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001563 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001564 mSamplersPS[i].textureType = (TextureType) textureType;
1565 }
1566
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001567 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001568 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001569 stream.read(&mSamplersVS[i].active);
1570 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571
1572 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001573 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001574 mSamplersVS[i].textureType = (TextureType) textureType;
1575 }
1576
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001577 stream.read(&mUsedVertexSamplerRange);
1578 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001579 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001580 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001581
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001582 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001583 stream.read(&size);
1584 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001585 {
1586 infoLog.append("Invalid program binary.");
1587 return false;
1588 }
1589
1590 mUniforms.resize(size);
1591 for (unsigned int i = 0; i < size; ++i)
1592 {
1593 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001594 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001595 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001596 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001597 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001600 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001601 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001602 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001603 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001604
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001605 int offset;
1606 int arrayStride;
1607 int matrixStride;
1608 bool isRowMajorMatrix;
1609
1610 stream.read(&offset);
1611 stream.read(&arrayStride);
1612 stream.read(&matrixStride);
1613 stream.read(&isRowMajorMatrix);
1614
1615 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1616
1617 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001619 stream.read(&mUniforms[i]->psRegisterIndex);
1620 stream.read(&mUniforms[i]->vsRegisterIndex);
1621 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001622 }
1623
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.read(&size);
1625 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001626 {
1627 infoLog.append("Invalid program binary.");
1628 return false;
1629 }
1630
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001631 mUniformBlocks.resize(size);
1632 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1633 {
1634 std::string name;
1635 unsigned int elementIndex;
1636 unsigned int dataSize;
1637
1638 stream.read(&name);
1639 stream.read(&elementIndex);
1640 stream.read(&dataSize);
1641
1642 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1643
1644 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1645 stream.read(&uniformBlock.psRegisterIndex);
1646 stream.read(&uniformBlock.vsRegisterIndex);
1647
1648 size_t numMembers;
1649 stream.read(&numMembers);
1650 uniformBlock.memberUniformIndexes.resize(numMembers);
1651 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1652 {
1653 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1654 }
1655 }
1656
1657 stream.read(&size);
1658 if (stream.error())
1659 {
1660 infoLog.append("Invalid program binary.");
1661 return false;
1662 }
1663
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664 mUniformIndex.resize(size);
1665 for (unsigned int i = 0; i < size; ++i)
1666 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&mUniformIndex[i].name);
1668 stream.read(&mUniformIndex[i].element);
1669 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001670 }
1671
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
1675 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001676 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001677
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001678 unsigned int geometryShaderSize;
1679 stream.read(&geometryShaderSize);
1680
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682
daniel@transgaming.com36038542012-11-28 20:59:26 +00001683 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684 ptr += sizeof(GUID);
1685
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001686 GUID identifier = mRenderer->getAdapterIdentifier();
1687 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 {
1689 infoLog.append("Invalid program binary.");
1690 return false;
1691 }
1692
1693 const char *pixelShaderFunction = ptr;
1694 ptr += pixelShaderSize;
1695
1696 const char *vertexShaderFunction = ptr;
1697 ptr += vertexShaderSize;
1698
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001699 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1700 ptr += geometryShaderSize;
1701
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001702 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001703 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001704 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705 {
1706 infoLog.append("Could not create pixel shader.");
1707 return false;
1708 }
1709
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001710 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001711 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001712 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001713 {
1714 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001715 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001716 mPixelExecutable = NULL;
1717 return false;
1718 }
1719
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001720 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1721 {
1722 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1723 geometryShaderSize, rx::SHADER_GEOMETRY);
1724 if (!mGeometryExecutable)
1725 {
1726 infoLog.append("Could not create geometry shader.");
1727 delete mPixelExecutable;
1728 mPixelExecutable = NULL;
1729 delete mVertexExecutable;
1730 mVertexExecutable = NULL;
1731 return false;
1732 }
1733 }
1734 else
1735 {
1736 mGeometryExecutable = NULL;
1737 }
1738
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001739 return true;
1740}
1741
1742bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1743{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001744 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001746 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001747 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001748 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001749
1750 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1751 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001752 stream.write(mLinkedAttribute[i].type);
1753 stream.write(mLinkedAttribute[i].name);
1754 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001755 }
1756
1757 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1758 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001759 stream.write(mSamplersPS[i].active);
1760 stream.write(mSamplersPS[i].logicalTextureUnit);
1761 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 }
1763
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001764 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.write(mSamplersVS[i].active);
1767 stream.write(mSamplersVS[i].logicalTextureUnit);
1768 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769 }
1770
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001771 stream.write(mUsedVertexSamplerRange);
1772 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001773 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001774 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001777 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001779 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001781 stream.write(uniform.type);
1782 stream.write(uniform.precision);
1783 stream.write(uniform.name);
1784 stream.write(uniform.arraySize);
1785 stream.write(uniform.blockIndex);
1786
1787 stream.write(uniform.blockInfo.offset);
1788 stream.write(uniform.blockInfo.arrayStride);
1789 stream.write(uniform.blockInfo.matrixStride);
1790 stream.write(uniform.blockInfo.isRowMajorMatrix);
1791
1792 stream.write(uniform.psRegisterIndex);
1793 stream.write(uniform.vsRegisterIndex);
1794 stream.write(uniform.registerCount);
1795 }
1796
1797 stream.write(mUniformBlocks.size());
1798 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1799 {
1800 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1801
1802 stream.write(uniformBlock.name);
1803 stream.write(uniformBlock.elementIndex);
1804 stream.write(uniformBlock.dataSize);
1805
1806 stream.write(uniformBlock.memberUniformIndexes.size());
1807 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1808 {
1809 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1810 }
1811
1812 stream.write(uniformBlock.psRegisterIndex);
1813 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 }
1815
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1818 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001819 stream.write(mUniformIndex[i].name);
1820 stream.write(mUniformIndex[i].element);
1821 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822 }
1823
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001824 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001826
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001827 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001828 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001830 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1831 stream.write(geometryShaderSize);
1832
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001833 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001835 GLsizei streamLength = stream.length();
1836 const void *streamData = stream.data();
1837
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001838 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001839 if (totalLength > bufSize)
1840 {
1841 if (length)
1842 {
1843 *length = 0;
1844 }
1845
1846 return false;
1847 }
1848
1849 if (binary)
1850 {
1851 char *ptr = (char*) binary;
1852
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001853 memcpy(ptr, streamData, streamLength);
1854 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001855
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001856 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857 ptr += sizeof(GUID);
1858
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001859 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001860 ptr += pixelShaderSize;
1861
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001862 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001863 ptr += vertexShaderSize;
1864
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001865 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1866 {
1867 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1868 ptr += geometryShaderSize;
1869 }
1870
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001871 ASSERT(ptr - totalLength == binary);
1872 }
1873
1874 if (length)
1875 {
1876 *length = totalLength;
1877 }
1878
1879 return true;
1880}
1881
1882GLint ProgramBinary::getLength()
1883{
1884 GLint length;
1885 if (save(NULL, INT_MAX, &length))
1886 {
1887 return length;
1888 }
1889 else
1890 {
1891 return 0;
1892 }
1893}
1894
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001895bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001896{
1897 if (!fragmentShader || !fragmentShader->isCompiled())
1898 {
1899 return false;
1900 }
1901
1902 if (!vertexShader || !vertexShader->isCompiled())
1903 {
1904 return false;
1905 }
1906
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001907 mShaderVersion = vertexShader->getShaderVersion();
1908
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001909 std::string pixelHLSL = fragmentShader->getHLSL();
1910 std::string vertexHLSL = vertexShader->getHLSL();
1911
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001912 // Map the varyings to the register file
1913 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1914 int registers = packVaryings(infoLog, packing, fragmentShader);
1915
1916 if (registers < 0)
1917 {
1918 return false;
1919 }
1920
1921 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001922 {
1923 return false;
1924 }
1925
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001926 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001927 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1928 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001929
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001930 if (usesGeometryShader())
1931 {
1932 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1933 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1934 }
1935
1936 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001937 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001938 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001939 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001940
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001941 delete mVertexExecutable;
1942 mVertexExecutable = NULL;
1943 delete mPixelExecutable;
1944 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001945 delete mGeometryExecutable;
1946 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001947 }
1948
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001949 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1950 {
1951 success = false;
1952 }
1953
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001954 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001955 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001956 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001957 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001958
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001959 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1960 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1961 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001962 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1963 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1964 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 +00001965 }
1966
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001967 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1968 {
1969 success = false;
1970 }
1971
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001972 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001973}
1974
1975// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001976bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001977{
1978 unsigned int usedLocations = 0;
1979
1980 // Link attributes that have a binding location
1981 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1982 {
1983 int location = attributeBindings.getAttributeBinding(attribute->name);
1984
1985 if (location != -1) // Set by glBindAttribLocation
1986 {
1987 if (!mLinkedAttribute[location].name.empty())
1988 {
1989 // Multiple active attributes bound to the same location; not an error
1990 }
1991
1992 mLinkedAttribute[location] = *attribute;
1993
1994 int rows = VariableRowCount(attribute->type);
1995
1996 if (rows + location > MAX_VERTEX_ATTRIBS)
1997 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001998 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 +00001999
2000 return false;
2001 }
2002
2003 for (int i = 0; i < rows; i++)
2004 {
2005 usedLocations |= 1 << (location + i);
2006 }
2007 }
2008 }
2009
2010 // Link attributes that don't have a binding location
2011 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2012 {
2013 int location = attributeBindings.getAttributeBinding(attribute->name);
2014
2015 if (location == -1) // Not set by glBindAttribLocation
2016 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002017 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002018 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2019
2020 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2021 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002022 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002023
2024 return false; // Fail to link
2025 }
2026
2027 mLinkedAttribute[availableIndex] = *attribute;
2028 }
2029 }
2030
2031 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2032 {
2033 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002034 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002035
2036 for (int r = 0; r < rows; r++)
2037 {
2038 mSemanticIndex[attributeIndex++] = index++;
2039 }
2040 }
2041
2042 return true;
2043}
2044
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002045bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2046{
2047 if (vertexUniform.type != fragmentUniform.type)
2048 {
2049 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2050 return false;
2051 }
2052 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2053 {
2054 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2055 return false;
2056 }
2057 else if (vertexUniform.precision != fragmentUniform.precision)
2058 {
2059 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2060 return false;
2061 }
2062 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2063 {
2064 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2065 }
2066
2067 const unsigned int numMembers = vertexUniform.fields.size();
2068 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2069 {
2070 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2071 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2072
2073 if (vertexMember.name != fragmentMember.name)
2074 {
2075 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2076 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2077 return false;
2078 }
2079
2080 const std::string memberName = uniformName + "." + vertexUniform.name;
2081 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2082 {
2083 return false;
2084 }
2085 }
2086
2087 return true;
2088}
2089
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002090bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002091{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002092 // Check that uniforms defined in the vertex and fragment shaders are identical
2093 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2094 UniformMap linkedUniforms;
2095
2096 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2097 {
2098 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2099 linkedUniforms[vertexUniform.name] = &vertexUniform;
2100 }
2101
2102 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2103 {
2104 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2105 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2106 if (entry != linkedUniforms.end())
2107 {
2108 const sh::Uniform &vertexUniform = *entry->second;
2109 const std::string &uniformName = "uniform " + vertexUniform.name;
2110 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2111 {
2112 return false;
2113 }
2114 }
2115 }
2116
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002117 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002118 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002119 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002120 {
2121 return false;
2122 }
2123 }
2124
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002125 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002126 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002127 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002128 {
2129 return false;
2130 }
2131 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002132
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002133 return true;
2134}
2135
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002136int totalRegisterCount(const sh::Uniform &uniform)
2137{
2138 int registerCount = 0;
2139
2140 if (!uniform.fields.empty())
2141 {
2142 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2143 {
2144 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2145 }
2146 }
2147 else
2148 {
2149 registerCount = 1;
2150 }
2151
2152 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2153}
2154
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002155bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002156{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002157 if (!constant.fields.empty())
2158 {
2159 if (constant.arraySize > 0)
2160 {
2161 unsigned int elementRegisterIndex = constant.registerIndex;
2162
2163 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2164 {
2165 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2166 {
2167 const sh::Uniform &field = constant.fields[fieldIndex];
2168 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2169 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2170 if (!defineUniform(shader, fieldUniform, infoLog))
2171 {
2172 return false;
2173 }
2174 elementRegisterIndex += totalRegisterCount(field);
2175 }
2176 }
2177 }
2178 else
2179 {
2180 unsigned int fieldRegisterIndex = constant.registerIndex;
2181
2182 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2183 {
2184 const sh::Uniform &field = constant.fields[fieldIndex];
2185 const std::string &uniformName = constant.name + "." + field.name;
2186
2187 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2188 fieldUniform.fields = field.fields;
2189
2190 if (!defineUniform(shader, fieldUniform, infoLog))
2191 {
2192 return false;
2193 }
2194 fieldRegisterIndex += totalRegisterCount(field);
2195 }
2196 }
2197
2198 return true;
2199 }
2200
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002201 if (constant.type == GL_SAMPLER_2D ||
2202 constant.type == GL_SAMPLER_CUBE)
2203 {
2204 unsigned int samplerIndex = constant.registerIndex;
2205
2206 do
2207 {
2208 if (shader == GL_VERTEX_SHADER)
2209 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002210 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002211 {
2212 mSamplersVS[samplerIndex].active = true;
2213 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2214 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2215 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2216 }
2217 else
2218 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002219 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002220 return false;
2221 }
2222 }
2223 else if (shader == GL_FRAGMENT_SHADER)
2224 {
2225 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2226 {
2227 mSamplersPS[samplerIndex].active = true;
2228 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2229 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2230 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2231 }
2232 else
2233 {
2234 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2235 return false;
2236 }
2237 }
2238 else UNREACHABLE();
2239
2240 samplerIndex++;
2241 }
2242 while (samplerIndex < constant.registerIndex + constant.arraySize);
2243 }
2244
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002245 Uniform *uniform = NULL;
2246 GLint location = getUniformLocation(constant.name);
2247
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002248 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002249 {
2250 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002251 }
2252 else
2253 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002254 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002255 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002256
2257 if (!uniform)
2258 {
2259 return false;
2260 }
2261
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002262 if (shader == GL_FRAGMENT_SHADER)
2263 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002264 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002265 }
2266 else if (shader == GL_VERTEX_SHADER)
2267 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002268 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002269 }
2270 else UNREACHABLE();
2271
2272 if (location >= 0)
2273 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002274 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002275 }
2276
2277 mUniforms.push_back(uniform);
2278 unsigned int uniformIndex = mUniforms.size() - 1;
2279
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002280 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002281 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002282 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002283 }
2284
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002285 if (shader == GL_VERTEX_SHADER)
2286 {
2287 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2288 {
2289 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2290 return false;
2291 }
2292 }
2293 else if (shader == GL_FRAGMENT_SHADER)
2294 {
2295 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2296 {
2297 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2298 return false;
2299 }
2300 }
2301 else UNREACHABLE();
2302
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002303 return true;
2304}
2305
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002306bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2307{
2308 const char* blockName = vertexInterfaceBlock.name.c_str();
2309
2310 // validate blocks for the same member types
2311 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2312 {
2313 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2314 return false;
2315 }
2316
2317 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2318 {
2319 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2320 return false;
2321 }
2322
2323 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2324 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2325 {
2326 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2327 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2328
2329 if (vertexMember.name != fragmentMember.name)
2330 {
2331 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2332 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2333 return false;
2334 }
2335
2336 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2337 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2338 {
2339 return false;
2340 }
2341 }
2342
2343 return true;
2344}
2345
2346bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2347{
2348 // Check that interface blocks defined in the vertex and fragment shaders are identical
2349 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2350 UniformBlockMap linkedUniformBlocks;
2351
2352 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2353 {
2354 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2355 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2356 }
2357
2358 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2359 {
2360 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2361 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2362 if (entry != linkedUniformBlocks.end())
2363 {
2364 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2365 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2366 {
2367 return false;
2368 }
2369 }
2370 }
2371
2372 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2373 {
2374 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2375 {
2376 return false;
2377 }
2378 }
2379
2380 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2381 {
2382 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2383 {
2384 return false;
2385 }
2386 }
2387
2388 return true;
2389}
2390
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002391void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2392{
2393 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2394 {
2395 const sh::Uniform &uniform = uniforms[uniformIndex];
2396
2397 if (!uniform.fields.empty())
2398 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002399 if (uniform.arraySize > 0)
2400 {
2401 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2402 {
2403 const std::string uniformElementName = uniform.name + "[" + str(arrayElement) + "]";
2404 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2405 }
2406 }
2407 else
2408 {
2409 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2410 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002411 }
2412 else
2413 {
2414 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2415 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2416 blockIndex, **blockInfoItr);
2417
2418 // add to uniform list, but not index, since uniform block uniforms have no location
2419 blockUniformIndexes->push_back(mUniforms.size());
2420 mUniforms.push_back(newUniform);
2421 (*blockInfoItr)++;
2422 }
2423 }
2424}
2425
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002426bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2427{
2428 // create uniform block entries if they do not exist
2429 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2430 {
2431 std::vector<unsigned int> blockUniformIndexes;
2432 const unsigned int blockIndex = mUniformBlocks.size();
2433
2434 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002435 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2436 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002437
2438 // create all the uniform blocks
2439 if (interfaceBlock.arraySize > 0)
2440 {
2441 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2442 {
2443 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2444 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2445 mUniformBlocks.push_back(newUniformBlock);
2446 }
2447 }
2448 else
2449 {
2450 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2451 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2452 mUniformBlocks.push_back(newUniformBlock);
2453 }
2454 }
2455
2456 // Assign registers to the uniform blocks
2457 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2458 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2459 ASSERT(blockIndex != GL_INVALID_INDEX);
2460 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2461
2462 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2463 {
2464 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2465 ASSERT(uniformBlock->name == interfaceBlock.name);
2466
2467 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2468 {
2469 return false;
2470 }
2471 }
2472
2473 return true;
2474}
2475
2476bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2477{
2478 if (shader == GL_VERTEX_SHADER)
2479 {
2480 uniformBlock->vsRegisterIndex = registerIndex;
2481 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2482
2483 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2484 {
2485 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2486 return false;
2487 }
2488 }
2489 else if (shader == GL_FRAGMENT_SHADER)
2490 {
2491 uniformBlock->psRegisterIndex = registerIndex;
2492 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2493
2494 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2495 {
2496 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2497 return false;
2498 }
2499 }
2500 else UNREACHABLE();
2501
2502 return true;
2503}
2504
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002505std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2506{
2507 // for now we only handle point sprite emulation
2508 ASSERT(usesPointSpriteEmulation());
2509 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2510}
2511
2512std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2513{
2514 ASSERT(registers >= 0);
2515 ASSERT(vertexShader->mUsesPointSize);
2516 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2517
2518 std::string geomHLSL;
2519
2520 std::string varyingSemantic = "TEXCOORD";
2521
2522 std::string fragCoordSemantic;
2523 std::string pointCoordSemantic;
2524
2525 int reservedRegisterIndex = registers;
2526
2527 if (fragmentShader->mUsesFragCoord)
2528 {
2529 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2530 }
2531
2532 if (fragmentShader->mUsesPointCoord)
2533 {
2534 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2535 }
2536
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002537 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2538 "\n"
2539 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002540 "{\n";
2541
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002542 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002543
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002544 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002545
2546 if (fragmentShader->mUsesFragCoord)
2547 {
2548 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2549 }
2550
2551 geomHLSL += " float gl_PointSize : PSIZE;\n"
2552 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002553 "};\n"
2554 "\n"
2555 "struct GS_OUTPUT\n"
2556 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002557
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002558 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002559
2560 if (fragmentShader->mUsesFragCoord)
2561 {
2562 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2563 }
2564
2565 if (fragmentShader->mUsesPointCoord)
2566 {
2567 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2568 }
2569
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002570 geomHLSL += " float gl_PointSize : PSIZE;\n"
2571 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002572 "};\n"
2573 "\n"
2574 "static float2 pointSpriteCorners[] = \n"
2575 "{\n"
2576 " float2( 0.5f, -0.5f),\n"
2577 " float2( 0.5f, 0.5f),\n"
2578 " float2(-0.5f, -0.5f),\n"
2579 " float2(-0.5f, 0.5f)\n"
2580 "};\n"
2581 "\n"
2582 "static float2 pointSpriteTexcoords[] = \n"
2583 "{\n"
2584 " float2(1.0f, 1.0f),\n"
2585 " float2(1.0f, 0.0f),\n"
2586 " float2(0.0f, 1.0f),\n"
2587 " float2(0.0f, 0.0f)\n"
2588 "};\n"
2589 "\n"
2590 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2591 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2592 "\n"
2593 "[maxvertexcount(4)]\n"
2594 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2595 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002596 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2597 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002598
2599 for (int r = 0; r < registers; r++)
2600 {
2601 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2602 }
2603
2604 if (fragmentShader->mUsesFragCoord)
2605 {
2606 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2607 }
2608
2609 geomHLSL += " \n"
2610 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2611 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002612 " 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 +00002613
2614 for (int corner = 0; corner < 4; corner++)
2615 {
2616 geomHLSL += " \n"
2617 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2618
2619 if (fragmentShader->mUsesPointCoord)
2620 {
2621 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2622 }
2623
2624 geomHLSL += " outStream.Append(output);\n";
2625 }
2626
2627 geomHLSL += " \n"
2628 " outStream.RestartStrip();\n"
2629 "}\n";
2630
2631 return geomHLSL;
2632}
2633
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002634// This method needs to match OutputHLSL::decorate
2635std::string ProgramBinary::decorateAttribute(const std::string &name)
2636{
2637 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2638 {
2639 return "_" + name;
2640 }
2641
2642 return name;
2643}
2644
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002645bool ProgramBinary::isValidated() const
2646{
2647 return mValidated;
2648}
2649
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002650void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002651{
2652 // Skip over inactive attributes
2653 unsigned int activeAttribute = 0;
2654 unsigned int attribute;
2655 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2656 {
2657 if (mLinkedAttribute[attribute].name.empty())
2658 {
2659 continue;
2660 }
2661
2662 if (activeAttribute == index)
2663 {
2664 break;
2665 }
2666
2667 activeAttribute++;
2668 }
2669
2670 if (bufsize > 0)
2671 {
2672 const char *string = mLinkedAttribute[attribute].name.c_str();
2673
2674 strncpy(name, string, bufsize);
2675 name[bufsize - 1] = '\0';
2676
2677 if (length)
2678 {
2679 *length = strlen(name);
2680 }
2681 }
2682
2683 *size = 1; // Always a single 'type' instance
2684
2685 *type = mLinkedAttribute[attribute].type;
2686}
2687
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002688GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002689{
2690 int count = 0;
2691
2692 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2693 {
2694 if (!mLinkedAttribute[attributeIndex].name.empty())
2695 {
2696 count++;
2697 }
2698 }
2699
2700 return count;
2701}
2702
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002703GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002704{
2705 int maxLength = 0;
2706
2707 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2708 {
2709 if (!mLinkedAttribute[attributeIndex].name.empty())
2710 {
2711 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2712 }
2713 }
2714
2715 return maxLength;
2716}
2717
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002718void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002719{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002720 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002721
2722 if (bufsize > 0)
2723 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002724 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002725
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002726 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002727 {
2728 string += "[0]";
2729 }
2730
2731 strncpy(name, string.c_str(), bufsize);
2732 name[bufsize - 1] = '\0';
2733
2734 if (length)
2735 {
2736 *length = strlen(name);
2737 }
2738 }
2739
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002740 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002741
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002742 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002743}
2744
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002745GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002746{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002747 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002748}
2749
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002750GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002751{
2752 int maxLength = 0;
2753
2754 unsigned int numUniforms = mUniforms.size();
2755 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2756 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002757 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002758 {
2759 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2760 if (mUniforms[uniformIndex]->isArray())
2761 {
2762 length += 3; // Counting in "[0]".
2763 }
2764 maxLength = std::max(length, maxLength);
2765 }
2766 }
2767
2768 return maxLength;
2769}
2770
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002771GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2772{
2773 const gl::Uniform& uniform = *mUniforms[index];
2774
2775 switch (pname)
2776 {
2777 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2778 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002779 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 +00002780 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002781
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002782 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2783 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2784 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2785 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002786
2787 default:
2788 UNREACHABLE();
2789 break;
2790 }
2791 return 0;
2792}
2793
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002794void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2795{
2796 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2797
2798 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2799
2800 if (bufSize > 0)
2801 {
2802 std::string string = uniformBlock.name;
2803
2804 if (uniformBlock.isArrayElement())
2805 {
2806 string += "[" + str(uniformBlock.elementIndex) + "]";
2807 }
2808
2809 strncpy(uniformBlockName, string.c_str(), bufSize);
2810 uniformBlockName[bufSize - 1] = '\0';
2811
2812 if (length)
2813 {
2814 *length = strlen(uniformBlockName);
2815 }
2816 }
2817}
2818
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002819void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2820{
2821 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2822
2823 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2824
2825 switch (pname)
2826 {
2827 case GL_UNIFORM_BLOCK_DATA_SIZE:
2828 *params = static_cast<GLint>(uniformBlock.dataSize);
2829 break;
2830 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002831 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002832 break;
2833 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2834 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2835 break;
2836 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2837 {
2838 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2839 {
2840 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2841 }
2842 }
2843 break;
2844 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2845 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2846 break;
2847 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2848 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2849 break;
2850 default: UNREACHABLE();
2851 }
2852}
2853
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002854GLuint ProgramBinary::getActiveUniformBlockCount() const
2855{
2856 return mUniformBlocks.size();
2857}
2858
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002859GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2860{
2861 unsigned int maxLength = 0;
2862
2863 unsigned int numUniformBlocks = mUniformBlocks.size();
2864 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2865 {
2866 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2867 if (!uniformBlock.name.empty())
2868 {
2869 const unsigned int length = uniformBlock.name.length() + 1;
2870
2871 // Counting in "[0]".
2872 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2873
2874 maxLength = std::max(length + arrayLength, maxLength);
2875 }
2876 }
2877
2878 return maxLength;
2879}
2880
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002881void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002882{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002883 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002884 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002885 {
2886 mValidated = false;
2887 }
2888 else
2889 {
2890 mValidated = true;
2891 }
2892}
2893
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002894bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002895{
2896 // if any two active samplers in a program are of different types, but refer to the same
2897 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2898 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2899
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002900 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002901 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002902
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002903 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002904 {
2905 textureUnitType[i] = TEXTURE_UNKNOWN;
2906 }
2907
2908 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2909 {
2910 if (mSamplersPS[i].active)
2911 {
2912 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2913
2914 if (unit >= maxCombinedTextureImageUnits)
2915 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002916 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002917 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002918 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002919 }
2920
2921 return false;
2922 }
2923
2924 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2925 {
2926 if (mSamplersPS[i].textureType != textureUnitType[unit])
2927 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002928 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002929 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002930 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002931 }
2932
2933 return false;
2934 }
2935 }
2936 else
2937 {
2938 textureUnitType[unit] = mSamplersPS[i].textureType;
2939 }
2940 }
2941 }
2942
2943 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2944 {
2945 if (mSamplersVS[i].active)
2946 {
2947 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2948
2949 if (unit >= maxCombinedTextureImageUnits)
2950 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002951 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002952 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002953 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002954 }
2955
2956 return false;
2957 }
2958
2959 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2960 {
2961 if (mSamplersVS[i].textureType != textureUnitType[unit])
2962 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002963 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002964 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002965 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002966 }
2967
2968 return false;
2969 }
2970 }
2971 else
2972 {
2973 textureUnitType[unit] = mSamplersVS[i].textureType;
2974 }
2975 }
2976 }
2977
2978 return true;
2979}
2980
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002981ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2982{
2983}
2984
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002985struct AttributeSorter
2986{
2987 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2988 : originalIndices(semanticIndices)
2989 {
2990 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2991 {
2992 indices[i] = i;
2993 }
2994
2995 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2996 }
2997
2998 bool operator()(int a, int b)
2999 {
3000 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3001 }
3002
3003 int indices[MAX_VERTEX_ATTRIBS];
3004 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3005};
3006
3007void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3008{
3009 AttributeSorter sorter(mSemanticIndex);
3010
3011 int oldIndices[MAX_VERTEX_ATTRIBS];
3012 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3013
3014 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3015 {
3016 oldIndices[i] = mSemanticIndex[i];
3017 oldTranslatedAttributes[i] = attributes[i];
3018 }
3019
3020 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3021 {
3022 int oldIndex = sorter.indices[i];
3023 sortedSemanticIndices[i] = oldIndices[oldIndex];
3024 attributes[i] = oldTranslatedAttributes[oldIndex];
3025 }
3026}
3027
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003028}