blob: 4dd1de1b1b0840f5947f82c7c4379dba48538625 [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
Jamie Madill63491ea2013-06-06 11:56:45 -040039std::string arrayString(int i)
40{
41 return "[" + str(i) + "]";
42}
43
Jamie Madill46131a32013-06-20 11:55:50 -040044std::string arrayString(unsigned int i)
45{
46 return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
47}
48
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000049namespace gl_d3d
50{
51 std::string TypeString(GLenum type)
52 {
53 switch (type)
54 {
55 case GL_FLOAT: return "float";
56 case GL_FLOAT_VEC2: return "float2";
57 case GL_FLOAT_VEC3: return "float3";
58 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000059 case GL_INT: return "int";
60 case GL_INT_VEC2: return "int2";
61 case GL_INT_VEC3: return "int3";
62 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000063 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000064 case GL_UNSIGNED_INT_VEC2: return "uint2";
65 case GL_UNSIGNED_INT_VEC3: return "uint3";
66 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000067 case GL_FLOAT_MAT2: return "float2x2";
68 case GL_FLOAT_MAT3: return "float3x3";
69 case GL_FLOAT_MAT4: return "float4x4";
70 case GL_FLOAT_MAT2x3: return "float2x3";
71 case GL_FLOAT_MAT3x2: return "float3x2";
72 case GL_FLOAT_MAT2x4: return "float2x4";
73 case GL_FLOAT_MAT4x2: return "float4x2";
74 case GL_FLOAT_MAT3x4: return "float3x4";
75 case GL_FLOAT_MAT4x3: return "float4x3";
76 default: UNREACHABLE(); return "invalid-gl-type";
77 }
78 }
79}
80
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000081namespace
82{
83
84unsigned int parseAndStripArrayIndex(std::string* name)
85{
86 unsigned int subscript = GL_INVALID_INDEX;
87
88 // Strip any trailing array operator and retrieve the subscript
89 size_t open = name->find_last_of('[');
90 size_t close = name->find_last_of(']');
91 if (open != std::string::npos && close == name->length() - 1)
92 {
93 subscript = atoi(name->substr(open + 1).c_str());
94 name->erase(open);
95 }
96
97 return subscript;
98}
99
100}
101
Jamie Madill63491ea2013-06-06 11:56:45 -0400102VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000103 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000104{
105}
106
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000107unsigned int ProgramBinary::mCurrentSerial = 1;
108
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000109ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000110{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000111 mPixelExecutable = NULL;
112 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000113 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000114
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115 mValidated = false;
116
117 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
118 {
119 mSemanticIndex[index] = -1;
120 }
121
122 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
123 {
124 mSamplersPS[index].active = false;
125 }
126
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000127 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000128 {
129 mSamplersVS[index].active = false;
130 }
131
132 mUsedVertexSamplerRange = 0;
133 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000134 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000135 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136}
137
138ProgramBinary::~ProgramBinary()
139{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000140 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000141 mPixelExecutable = NULL;
142
daniel@transgaming.com95892412012-11-28 20:59:09 +0000143 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000144 mVertexExecutable = NULL;
145
146 delete mGeometryExecutable;
147 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000148
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000149 while (!mUniforms.empty())
150 {
151 delete mUniforms.back();
152 mUniforms.pop_back();
153 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000154
155 while (!mUniformBlocks.empty())
156 {
157 delete mUniformBlocks.back();
158 mUniformBlocks.pop_back();
159 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000160}
161
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000162unsigned int ProgramBinary::getSerial() const
163{
164 return mSerial;
165}
166
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000167int ProgramBinary::getShaderVersion() const
168{
169 return mShaderVersion;
170}
171
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000172unsigned int ProgramBinary::issueSerial()
173{
174 return mCurrentSerial++;
175}
176
daniel@transgaming.com95892412012-11-28 20:59:09 +0000177rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000178{
179 return mPixelExecutable;
180}
181
daniel@transgaming.com95892412012-11-28 20:59:09 +0000182rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000183{
184 return mVertexExecutable;
185}
186
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000187rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
188{
189 return mGeometryExecutable;
190}
191
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000192GLuint ProgramBinary::getAttributeLocation(const char *name)
193{
194 if (name)
195 {
196 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
197 {
198 if (mLinkedAttribute[index].name == std::string(name))
199 {
200 return index;
201 }
202 }
203 }
204
205 return -1;
206}
207
208int ProgramBinary::getSemanticIndex(int attributeIndex)
209{
210 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
211
212 return mSemanticIndex[attributeIndex];
213}
214
215// Returns one more than the highest sampler index used.
216GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
217{
218 switch (type)
219 {
220 case SAMPLER_PIXEL:
221 return mUsedPixelSamplerRange;
222 case SAMPLER_VERTEX:
223 return mUsedVertexSamplerRange;
224 default:
225 UNREACHABLE();
226 return 0;
227 }
228}
229
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000230bool ProgramBinary::usesPointSize() const
231{
232 return mUsesPointSize;
233}
234
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000235bool ProgramBinary::usesPointSpriteEmulation() const
236{
237 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
238}
239
240bool ProgramBinary::usesGeometryShader() const
241{
242 return usesPointSpriteEmulation();
243}
244
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000245// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
246// index (0-15 for the pixel shader and 0-3 for the vertex shader).
247GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
248{
249 GLint logicalTextureUnit = -1;
250
251 switch (type)
252 {
253 case SAMPLER_PIXEL:
254 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
255
256 if (mSamplersPS[samplerIndex].active)
257 {
258 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
259 }
260 break;
261 case SAMPLER_VERTEX:
262 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
263
264 if (mSamplersVS[samplerIndex].active)
265 {
266 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
267 }
268 break;
269 default: UNREACHABLE();
270 }
271
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000272 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000273 {
274 return logicalTextureUnit;
275 }
276
277 return -1;
278}
279
280// Returns the texture type for a given Direct3D 9 sampler type and
281// index (0-15 for the pixel shader and 0-3 for the vertex shader).
282TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
283{
284 switch (type)
285 {
286 case SAMPLER_PIXEL:
287 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
288 ASSERT(mSamplersPS[samplerIndex].active);
289 return mSamplersPS[samplerIndex].textureType;
290 case SAMPLER_VERTEX:
291 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
292 ASSERT(mSamplersVS[samplerIndex].active);
293 return mSamplersVS[samplerIndex].textureType;
294 default: UNREACHABLE();
295 }
296
297 return TEXTURE_2D;
298}
299
300GLint ProgramBinary::getUniformLocation(std::string name)
301{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000302 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000303
304 unsigned int numUniforms = mUniformIndex.size();
305 for (unsigned int location = 0; location < numUniforms; location++)
306 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000307 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000308 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000309 const int index = mUniformIndex[location].index;
310 const bool isArray = mUniforms[index]->isArray();
311
312 if ((isArray && mUniformIndex[location].element == subscript) ||
313 (subscript == GL_INVALID_INDEX))
314 {
315 return location;
316 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000317 }
318 }
319
320 return -1;
321}
322
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000323GLuint ProgramBinary::getUniformIndex(std::string name)
324{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000325 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000326
327 // The app is not allowed to specify array indices other than 0 for arrays of basic types
328 if (subscript != 0 && subscript != GL_INVALID_INDEX)
329 {
330 return GL_INVALID_INDEX;
331 }
332
333 unsigned int numUniforms = mUniforms.size();
334 for (unsigned int index = 0; index < numUniforms; index++)
335 {
336 if (mUniforms[index]->name == name)
337 {
338 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
339 {
340 return index;
341 }
342 }
343 }
344
345 return GL_INVALID_INDEX;
346}
347
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000348GLuint ProgramBinary::getUniformBlockIndex(std::string name)
349{
350 unsigned int subscript = parseAndStripArrayIndex(&name);
351
352 unsigned int numUniformBlocks = mUniformBlocks.size();
353 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
354 {
355 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
356 if (uniformBlock.name == name)
357 {
358 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
359 if (subscript == uniformBlock.elementIndex || arrayElementZero)
360 {
361 return blockIndex;
362 }
363 }
364 }
365
366 return GL_INVALID_INDEX;
367}
368
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000369UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
370{
371 ASSERT(blockIndex < mUniformBlocks.size());
372 return mUniformBlocks[blockIndex];
373}
374
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000375template <typename T>
376bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377{
378 if (location < 0 || location >= (int)mUniformIndex.size())
379 {
380 return false;
381 }
382
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000383 const int components = UniformComponentCount(targetUniformType);
384 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
385
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000386 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
387 targetUniform->dirty = true;
388
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000389 int elementCount = targetUniform->elementCount();
390
391 if (elementCount == 1 && count > 1)
392 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
393
394 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
395
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000396 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000397 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000398 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399
400 for (int i = 0; i < count; i++)
401 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000402 for (int c = 0; c < components; c++)
403 {
404 target[c] = v[c];
405 }
406 for (int c = components; c < 4; c++)
407 {
408 target[c] = 0;
409 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000410 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000411 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412 }
413 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000414 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000415 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000416 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000417
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000418 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000419 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000420 for (int c = 0; c < components; c++)
421 {
422 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
423 }
424 for (int c = components; c < 4; c++)
425 {
426 boolParams[c] = GL_FALSE;
427 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000428 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000429 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000430 }
431 }
432 else
433 {
434 return false;
435 }
436
437 return true;
438}
439
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000440bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
441{
442 return setUniform(location, count, v, GL_FLOAT);
443}
444
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445bool ProgramBinary::setUniform2fv(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_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448}
449
450bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
451{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000452 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000453}
454
455bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
456{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000457 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000458}
459
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000460template<typename T>
461void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000462{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000463 int copyWidth = std::min(targetHeight, srcWidth);
464 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465
466 for (int x = 0; x < copyWidth; x++)
467 {
468 for (int y = 0; y < copyHeight; y++)
469 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000470 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000471 }
472 }
473 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000474 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000475 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000476 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000477 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000478 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000479 }
480 }
481 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000482 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000483 {
484 for (int x = 0; x < targetWidth; x++)
485 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000486 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000487 }
488 }
489}
490
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000491template<typename T>
492void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
493{
494 int copyWidth = std::min(targetWidth, srcWidth);
495 int copyHeight = std::min(targetHeight, srcHeight);
496
497 for (int y = 0; y < copyHeight; y++)
498 {
499 for (int x = 0; x < copyWidth; x++)
500 {
501 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
502 }
503 }
504 // clear unfilled right side
505 for (int y = 0; y < copyHeight; y++)
506 {
507 for (int x = copyWidth; x < targetWidth; x++)
508 {
509 target[y * targetWidth + x] = static_cast<T>(0);
510 }
511 }
512 // clear unfilled bottom.
513 for (int y = copyHeight; y < targetHeight; y++)
514 {
515 for (int x = 0; x < targetWidth; x++)
516 {
517 target[y * targetWidth + x] = static_cast<T>(0);
518 }
519 }
520}
521
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000522template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000523bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524{
525 if (location < 0 || location >= (int)mUniformIndex.size())
526 {
527 return false;
528 }
529
530 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
531 targetUniform->dirty = true;
532
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000533 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000534 {
535 return false;
536 }
537
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000538 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000539
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000540 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000541 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
542
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000543 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000544 const unsigned int targetMatrixStride = (4 * rows);
545 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000546
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000547 for (int i = 0; i < count; i++)
548 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000549 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
550 if (transpose == GL_FALSE)
551 {
552 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
553 }
554 else
555 {
556 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
557 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000558 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000559 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560 }
561
562 return true;
563}
564
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000565bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000566{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000568}
569
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000570bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000571{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000572 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000573}
574
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000575bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000576{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000577 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578}
579
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000580bool ProgramBinary::setUniformMatrix2x3fv(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, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
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::setUniformMatrix3x2fv(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<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
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::setUniformMatrix2x4fv(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<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
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::setUniformMatrix4x2fv(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, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000598}
599
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000600bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000601{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000602 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000603}
604
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000605bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000606{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000607 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000608}
609
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000610bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
611{
612 if (location < 0 || location >= (int)mUniformIndex.size())
613 {
614 return false;
615 }
616
617 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
618 targetUniform->dirty = true;
619
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000620 int elementCount = targetUniform->elementCount();
621
622 if (elementCount == 1 && count > 1)
623 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
624
625 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
626
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000627 if (targetUniform->type == GL_INT ||
628 targetUniform->type == GL_SAMPLER_2D ||
629 targetUniform->type == GL_SAMPLER_CUBE)
630 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000631 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000632
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000633 for (int i = 0; i < count; i++)
634 {
635 target[0] = v[0];
636 target[1] = 0;
637 target[2] = 0;
638 target[3] = 0;
639 target += 4;
640 v += 1;
641 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000642 }
643 else if (targetUniform->type == GL_BOOL)
644 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000645 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000646
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000647 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000648 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000649 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
650 boolParams[1] = GL_FALSE;
651 boolParams[2] = GL_FALSE;
652 boolParams[3] = GL_FALSE;
653 boolParams += 4;
654 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000655 }
656 }
657 else
658 {
659 return false;
660 }
661
662 return true;
663}
664
665bool ProgramBinary::setUniform2iv(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_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668}
669
670bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
671{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000672 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000673}
674
675bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
676{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000677 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000678}
679
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000680bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
681{
682 return setUniform(location, count, v, GL_UNSIGNED_INT);
683}
684
685bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
686{
687 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
688}
689
690bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
691{
692 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
693}
694
695bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
696{
697 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
698}
699
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000700template <typename T>
701bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000702{
703 if (location < 0 || location >= (int)mUniformIndex.size())
704 {
705 return false;
706 }
707
708 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
709
710 // sized queries -- ensure the provided buffer is large enough
711 if (bufSize)
712 {
713 int requiredBytes = UniformExternalSize(targetUniform->type);
714 if (*bufSize < requiredBytes)
715 {
716 return false;
717 }
718 }
719
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000720 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000721 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000722 const int rows = VariableRowCount(targetUniform->type);
723 const int cols = VariableColumnCount(targetUniform->type);
724 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
725 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000726 else if (uniformType == UniformComponentType(targetUniform->type))
727 {
728 unsigned int size = UniformComponentCount(targetUniform->type);
729 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
730 size * sizeof(T));
731 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000732 else
733 {
734 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000735 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000736 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000737 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000738 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000740
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000741 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000742 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000743 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000744 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000745 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000746 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000747
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000748 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000749 {
750 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
751
752 for (unsigned int i = 0; i < size; i++)
753 {
754 params[i] = static_cast<T>(floatParams[i]);
755 }
756 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000757 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000758
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000759 case GL_INT:
760 {
761 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
762
763 for (unsigned int i = 0; i < size; i++)
764 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000765 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000766 }
767 }
768 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000769
770 case GL_UNSIGNED_INT:
771 {
772 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000773
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000774 for (unsigned int i = 0; i < size; i++)
775 {
776 params[i] = static_cast<T>(uintParams[i]);
777 }
778 }
779 break;
780
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000781 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000782 }
783 }
784
785 return true;
786}
787
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000788bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
789{
790 return getUniformv(location, bufSize, params, GL_FLOAT);
791}
792
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000793bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
794{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000795 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000796}
797
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000798bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
799{
800 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
801}
802
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000803void ProgramBinary::dirtyAllUniforms()
804{
805 unsigned int numUniforms = mUniforms.size();
806 for (unsigned int index = 0; index < numUniforms; index++)
807 {
808 mUniforms[index]->dirty = true;
809 }
810}
811
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000812// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000813void ProgramBinary::applyUniforms()
814{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000815 // Retrieve sampler uniform values
816 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
817 {
818 Uniform *targetUniform = *ub;
819
820 if (targetUniform->dirty)
821 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000822 if (targetUniform->type == GL_SAMPLER_2D ||
823 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000824 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000825 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000826 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000827
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000828 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000829 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000830 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000831
832 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000833 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000834 unsigned int samplerIndex = firstIndex + i;
835
836 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000837 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000838 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000839 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000840 }
841 }
842 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000843
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000844 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000845 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000846 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000847
848 for (int i = 0; i < count; i++)
849 {
850 unsigned int samplerIndex = firstIndex + i;
851
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000852 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000853 {
854 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000855 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000856 }
857 }
858 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000859 }
860 }
861 }
862
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000863 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000864}
865
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000866bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
867{
868 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
869 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
870
871 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
872 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
873
874 ASSERT(boundBuffers.size() == mUniformBlocks.size());
875
876 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
877 {
878 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
879 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
880
881 ASSERT(uniformBlock && uniformBuffer);
882
883 if (uniformBuffer->size() < uniformBlock->dataSize)
884 {
885 // undefined behaviour
886 return false;
887 }
888
889 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
890
891 if (uniformBlock->isReferencedByVertexShader())
892 {
893 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
894 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
895 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
896 vertexUniformBuffers[registerIndex] = uniformBuffer;
897 }
898
899 if (uniformBlock->isReferencedByFragmentShader())
900 {
901 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
902 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
903 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
904 fragmentUniformBuffers[registerIndex] = uniformBuffer;
905 }
906 }
907
908 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
909}
910
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000911// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
912// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000913int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000914{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000915 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000916
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000917 fragmentShader->resetVaryingsRegisterAssignment();
918
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000919 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
920 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000921 GLenum transposedType = TransposeMatrixType(varying->type);
922 int n = VariableRowCount(transposedType) * varying->size;
923 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000924 bool success = false;
925
926 if (m == 2 || m == 3 || m == 4)
927 {
928 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
929 {
930 bool available = true;
931
932 for (int y = 0; y < n && available; y++)
933 {
934 for (int x = 0; x < m && available; x++)
935 {
936 if (packing[r + y][x])
937 {
938 available = false;
939 }
940 }
941 }
942
943 if (available)
944 {
945 varying->reg = r;
946 varying->col = 0;
947
948 for (int y = 0; y < n; y++)
949 {
950 for (int x = 0; x < m; x++)
951 {
952 packing[r + y][x] = &*varying;
953 }
954 }
955
956 success = true;
957 }
958 }
959
960 if (!success && m == 2)
961 {
962 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
963 {
964 bool available = true;
965
966 for (int y = 0; y < n && available; y++)
967 {
968 for (int x = 2; x < 4 && available; x++)
969 {
970 if (packing[r + y][x])
971 {
972 available = false;
973 }
974 }
975 }
976
977 if (available)
978 {
979 varying->reg = r;
980 varying->col = 2;
981
982 for (int y = 0; y < n; y++)
983 {
984 for (int x = 2; x < 4; x++)
985 {
986 packing[r + y][x] = &*varying;
987 }
988 }
989
990 success = true;
991 }
992 }
993 }
994 }
995 else if (m == 1)
996 {
997 int space[4] = {0};
998
999 for (int y = 0; y < maxVaryingVectors; y++)
1000 {
1001 for (int x = 0; x < 4; x++)
1002 {
1003 space[x] += packing[y][x] ? 0 : 1;
1004 }
1005 }
1006
1007 int column = 0;
1008
1009 for (int x = 0; x < 4; x++)
1010 {
1011 if (space[x] >= n && space[x] < space[column])
1012 {
1013 column = x;
1014 }
1015 }
1016
1017 if (space[column] >= n)
1018 {
1019 for (int r = 0; r < maxVaryingVectors; r++)
1020 {
1021 if (!packing[r][column])
1022 {
1023 varying->reg = r;
1024
1025 for (int y = r; y < r + n; y++)
1026 {
1027 packing[y][column] = &*varying;
1028 }
1029
1030 break;
1031 }
1032 }
1033
1034 varying->col = column;
1035
1036 success = true;
1037 }
1038 }
1039 else UNREACHABLE();
1040
1041 if (!success)
1042 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001043 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044
1045 return -1;
1046 }
1047 }
1048
1049 // Return the number of used registers
1050 int registers = 0;
1051
1052 for (int r = 0; r < maxVaryingVectors; r++)
1053 {
1054 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1055 {
1056 registers++;
1057 }
1058 }
1059
1060 return registers;
1061}
1062
Jamie Madill46131a32013-06-20 11:55:50 -04001063void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1064{
1065 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1066
1067 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1068 {
1069 const sh::ShaderVariable &outputVariable = outputVars[outputVariableIndex];
1070 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1071
1072 if (outputVariable.arraySize > 0)
1073 {
1074 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1075 {
1076 const int location = baseLocation + elementIndex;
1077 ASSERT(mOutputVariables.count(location) == 0);
1078 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1079 }
1080 }
1081 else
1082 {
1083 ASSERT(mOutputVariables.count(baseLocation) == 0);
1084 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1085 }
1086 }
1087}
1088
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001089bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1090 std::string& pixelHLSL, std::string& vertexHLSL,
1091 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001092{
1093 if (pixelHLSL.empty() || vertexHLSL.empty())
1094 {
1095 return false;
1096 }
1097
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001098 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1099 bool usesFragColor = fragmentShader->mUsesFragColor;
1100 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001101 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001102 {
1103 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1104 return false;
1105 }
1106
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001107 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001108 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001109 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001110
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001111 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1112
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001113 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1114 // - with a 3.0 context, the output color is copied to channel 0
1115 // - with a 2.0 context, the output color is broadcast to all channels
1116 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1117 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1118
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001119 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001120 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001121 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001122
1123 return false;
1124 }
1125
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001126 vertexShader->resetVaryingsRegisterAssignment();
1127
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001128 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1129 {
1130 bool matched = false;
1131
1132 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1133 {
1134 if (output->name == input->name)
1135 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001136 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001137 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001138 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 +00001139
1140 return false;
1141 }
1142
1143 output->reg = input->reg;
1144 output->col = input->col;
1145
1146 matched = true;
1147 break;
1148 }
1149 }
1150
1151 if (!matched)
1152 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001153 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001154
1155 return false;
1156 }
1157 }
1158
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001159 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001160 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001161 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001162 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1163
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001164 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1165
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001166 // special varyings that use reserved registers
1167 int reservedRegisterIndex = registers;
1168 std::string fragCoordSemantic;
1169 std::string pointCoordSemantic;
1170
1171 if (fragmentShader->mUsesFragCoord)
1172 {
1173 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1174 }
1175
1176 if (fragmentShader->mUsesPointCoord)
1177 {
1178 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1179 // In DX11 we compute this in the GS.
1180 if (shaderModel == 3)
1181 {
1182 pointCoordSemantic = "TEXCOORD0";
1183 }
1184 else if (shaderModel >= 4)
1185 {
1186 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1187 }
1188 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001189
1190 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001191 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001192
1193 int semanticIndex = 0;
1194 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1195 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001196 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001197 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1198
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001199 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001200 }
1201
1202 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001203 "\n"
1204 "struct VS_OUTPUT\n"
1205 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001206
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001207 if (shaderModel < 4)
1208 {
1209 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1210 }
1211
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001212 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001213
1214 if (fragmentShader->mUsesFragCoord)
1215 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001216 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001217 }
1218
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001219 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001220 {
1221 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1222 }
1223
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001224 if (shaderModel >= 4)
1225 {
1226 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1227 }
1228
1229 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001230 "\n"
1231 "VS_OUTPUT main(VS_INPUT input)\n"
1232 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001233
1234 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1235 {
1236 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1237
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001238 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239 {
1240 vertexHLSL += "transpose";
1241 }
1242
1243 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1244 }
1245
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001246 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1247 {
1248 vertexHLSL += "\n"
1249 " dx_initConstantBuffers();\n";
1250 }
1251
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001252 if (shaderModel >= 4)
1253 {
1254 vertexHLSL += "\n"
1255 " gl_main();\n"
1256 "\n"
1257 " VS_OUTPUT output;\n"
1258 " output.gl_Position.x = gl_Position.x;\n"
1259 " output.gl_Position.y = -gl_Position.y;\n"
1260 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1261 " output.gl_Position.w = gl_Position.w;\n";
1262 }
1263 else
1264 {
1265 vertexHLSL += "\n"
1266 " gl_main();\n"
1267 "\n"
1268 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001269 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1270 " 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 +00001271 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1272 " output.gl_Position.w = gl_Position.w;\n";
1273 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001274
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001275 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001276 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001277 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278 }
1279
1280 if (fragmentShader->mUsesFragCoord)
1281 {
1282 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1283 }
1284
1285 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1286 {
1287 if (varying->reg >= 0)
1288 {
1289 for (int i = 0; i < varying->size; i++)
1290 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001291 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001292
1293 for (int j = 0; j < rows; j++)
1294 {
1295 int r = varying->reg + i * rows + j;
1296 vertexHLSL += " output.v" + str(r);
1297
1298 bool sharedRegister = false; // Register used by multiple varyings
1299
1300 for (int x = 0; x < 4; x++)
1301 {
1302 if (packing[r][x] && packing[r][x] != packing[r][0])
1303 {
1304 sharedRegister = true;
1305 break;
1306 }
1307 }
1308
1309 if(sharedRegister)
1310 {
1311 vertexHLSL += ".";
1312
1313 for (int x = 0; x < 4; x++)
1314 {
1315 if (packing[r][x] == &*varying)
1316 {
1317 switch(x)
1318 {
1319 case 0: vertexHLSL += "x"; break;
1320 case 1: vertexHLSL += "y"; break;
1321 case 2: vertexHLSL += "z"; break;
1322 case 3: vertexHLSL += "w"; break;
1323 }
1324 }
1325 }
1326 }
1327
1328 vertexHLSL += " = " + varying->name;
1329
1330 if (varying->array)
1331 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001332 vertexHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001333 }
1334
1335 if (rows > 1)
1336 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001337 vertexHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001338 }
1339
1340 vertexHLSL += ";\n";
1341 }
1342 }
1343 }
1344 }
1345
1346 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001347 " return output;\n"
1348 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349
1350 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001351 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001352
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001353 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001354
1355 if (fragmentShader->mUsesFragCoord)
1356 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001357 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001358 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001359
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001360 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1361 {
1362 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1363 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001364
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001365 // Must consume the PSIZE element if the geometry shader is not active
1366 // We won't know if we use a GS until we draw
1367 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1368 {
1369 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1370 }
1371
1372 if (fragmentShader->mUsesFragCoord)
1373 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001374 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001375 {
1376 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1377 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001378 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001379 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001380 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1381 }
1382 }
1383
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001384 pixelHLSL += "};\n"
1385 "\n"
1386 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001387 "{\n";
1388
Jamie Madill46131a32013-06-20 11:55:50 -04001389 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001390 {
Jamie Madill46131a32013-06-20 11:55:50 -04001391 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1392 {
1393 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1394 }
1395 }
1396 else
1397 {
1398 defineOutputVariables(fragmentShader);
1399
1400 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1401 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1402 {
1403 const VariableLocation &outputLocation = locationIt->second;
1404 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1405 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1406
1407 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1408 " out_" + outputLocation.name + elementString +
1409 " : " + targetSemantic + str(locationIt->first) + ";\n";
1410 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001411 }
1412
1413 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001414 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001415
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001416 if (fragmentShader->mUsesFrontFacing)
1417 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001418 if (shaderModel >= 4)
1419 {
1420 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1421 "{\n";
1422 }
1423 else
1424 {
1425 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1426 "{\n";
1427 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001428 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001429 else
1430 {
1431 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1432 "{\n";
1433 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001434
1435 if (fragmentShader->mUsesFragCoord)
1436 {
1437 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1438
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001439 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001440 {
1441 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1442 " gl_FragCoord.y = input.dx_VPos.y;\n";
1443 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001444 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001445 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001446 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001447 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001448 }
1449 else
1450 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001451 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1452 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1453 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001454 }
1455
daniel@transgaming.com12985182012-12-20 20:56:31 +00001456 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001457 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458 }
1459
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001460 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001461 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001462 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1463 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001464 }
1465
1466 if (fragmentShader->mUsesFrontFacing)
1467 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001468 if (shaderModel <= 3)
1469 {
1470 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1471 }
1472 else
1473 {
1474 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1475 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001476 }
1477
1478 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1479 {
1480 if (varying->reg >= 0)
1481 {
1482 for (int i = 0; i < varying->size; i++)
1483 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001484 GLenum transposedType = TransposeMatrixType(varying->type);
1485 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001486 for (int j = 0; j < rows; j++)
1487 {
1488 std::string n = str(varying->reg + i * rows + j);
1489 pixelHLSL += " " + varying->name;
1490
1491 if (varying->array)
1492 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001493 pixelHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001494 }
1495
1496 if (rows > 1)
1497 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001498 pixelHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001499 }
1500
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001501 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001502 {
1503 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1504 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1505 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1506 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1507 default: UNREACHABLE();
1508 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001509 }
1510 }
1511 }
1512 else UNREACHABLE();
1513 }
1514
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001515 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1516 {
1517 pixelHLSL += "\n"
1518 " dx_initConstantBuffers();\n";
1519 }
1520
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001521 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001522 " gl_main();\n"
1523 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001524 " PS_OUTPUT output;\n";
1525
Jamie Madill46131a32013-06-20 11:55:50 -04001526 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001527 {
Jamie Madill46131a32013-06-20 11:55:50 -04001528 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1529 {
1530 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001531
Jamie Madill46131a32013-06-20 11:55:50 -04001532 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1533 }
1534 }
1535 else
1536 {
1537 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1538 {
1539 const VariableLocation &outputLocation = locationIt->second;
1540 const std::string &variableName = "out_" + outputLocation.name;
1541 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1542 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1543
1544 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1545 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001546 }
1547
1548 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001549 " return output;\n"
1550 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001551
1552 return true;
1553}
1554
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001555std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1556{
1557 std::string varyingHLSL;
1558
1559 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1560 {
1561 if (varying->reg >= 0)
1562 {
1563 for (int i = 0; i < varying->size; i++)
1564 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001565 GLenum transposedType = TransposeMatrixType(varying->type);
1566 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001567 for (int j = 0; j < rows; j++)
1568 {
1569 switch (varying->interpolation)
1570 {
1571 case Smooth: varyingHLSL += " "; break;
1572 case Flat: varyingHLSL += " nointerpolation "; break;
1573 case Centroid: varyingHLSL += " centroid "; break;
1574 default: UNREACHABLE();
1575 }
1576
1577 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001578 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001579
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001580 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001581 }
1582 }
1583 }
1584 else UNREACHABLE();
1585 }
1586
1587 return varyingHLSL;
1588}
1589
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001590bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1591{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001592 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001593
1594 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001595 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001596 if (format != GL_PROGRAM_BINARY_ANGLE)
1597 {
1598 infoLog.append("Invalid program binary format.");
1599 return false;
1600 }
1601
1602 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001603 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001604 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605 {
1606 infoLog.append("Invalid program binary version.");
1607 return false;
1608 }
1609
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001610 int compileFlags = 0;
1611 stream.read(&compileFlags);
1612 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1613 {
1614 infoLog.append("Mismatched compilation flags.");
1615 return false;
1616 }
1617
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1619 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001620 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&name);
1623 mLinkedAttribute[i].name = name;
1624 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001625 }
1626
1627 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1628 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001629 stream.read(&mSamplersPS[i].active);
1630 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631
1632 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001633 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 mSamplersPS[i].textureType = (TextureType) textureType;
1635 }
1636
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001637 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001639 stream.read(&mSamplersVS[i].active);
1640 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641
1642 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001643 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001644 mSamplersVS[i].textureType = (TextureType) textureType;
1645 }
1646
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.read(&mUsedVertexSamplerRange);
1648 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001649 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001650 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001652 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001653 stream.read(&size);
1654 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 {
1656 infoLog.append("Invalid program binary.");
1657 return false;
1658 }
1659
1660 mUniforms.resize(size);
1661 for (unsigned int i = 0; i < size; ++i)
1662 {
1663 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001664 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001665 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001667 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001670 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001671 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001673 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001675 int offset;
1676 int arrayStride;
1677 int matrixStride;
1678 bool isRowMajorMatrix;
1679
1680 stream.read(&offset);
1681 stream.read(&arrayStride);
1682 stream.read(&matrixStride);
1683 stream.read(&isRowMajorMatrix);
1684
1685 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1686
1687 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001689 stream.read(&mUniforms[i]->psRegisterIndex);
1690 stream.read(&mUniforms[i]->vsRegisterIndex);
1691 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001692 }
1693
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001694 stream.read(&size);
1695 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696 {
1697 infoLog.append("Invalid program binary.");
1698 return false;
1699 }
1700
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001701 mUniformBlocks.resize(size);
1702 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1703 {
1704 std::string name;
1705 unsigned int elementIndex;
1706 unsigned int dataSize;
1707
1708 stream.read(&name);
1709 stream.read(&elementIndex);
1710 stream.read(&dataSize);
1711
1712 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1713
1714 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1715 stream.read(&uniformBlock.psRegisterIndex);
1716 stream.read(&uniformBlock.vsRegisterIndex);
1717
1718 size_t numMembers;
1719 stream.read(&numMembers);
1720 uniformBlock.memberUniformIndexes.resize(numMembers);
1721 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1722 {
1723 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1724 }
1725 }
1726
1727 stream.read(&size);
1728 if (stream.error())
1729 {
1730 infoLog.append("Invalid program binary.");
1731 return false;
1732 }
1733
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001734 mUniformIndex.resize(size);
1735 for (unsigned int i = 0; i < size; ++i)
1736 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001737 stream.read(&mUniformIndex[i].name);
1738 stream.read(&mUniformIndex[i].element);
1739 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740 }
1741
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001742 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001744
1745 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001746 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001747
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001748 unsigned int geometryShaderSize;
1749 stream.read(&geometryShaderSize);
1750
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001751 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752
daniel@transgaming.com36038542012-11-28 20:59:26 +00001753 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754 ptr += sizeof(GUID);
1755
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001756 GUID identifier = mRenderer->getAdapterIdentifier();
1757 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758 {
1759 infoLog.append("Invalid program binary.");
1760 return false;
1761 }
1762
1763 const char *pixelShaderFunction = ptr;
1764 ptr += pixelShaderSize;
1765
1766 const char *vertexShaderFunction = ptr;
1767 ptr += vertexShaderSize;
1768
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001769 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1770 ptr += geometryShaderSize;
1771
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001772 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001773 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001774 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775 {
1776 infoLog.append("Could not create pixel shader.");
1777 return false;
1778 }
1779
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001780 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001781 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001782 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783 {
1784 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001785 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786 mPixelExecutable = NULL;
1787 return false;
1788 }
1789
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001790 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1791 {
1792 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1793 geometryShaderSize, rx::SHADER_GEOMETRY);
1794 if (!mGeometryExecutable)
1795 {
1796 infoLog.append("Could not create geometry shader.");
1797 delete mPixelExecutable;
1798 mPixelExecutable = NULL;
1799 delete mVertexExecutable;
1800 mVertexExecutable = NULL;
1801 return false;
1802 }
1803 }
1804 else
1805 {
1806 mGeometryExecutable = NULL;
1807 }
1808
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001809 return true;
1810}
1811
1812bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1813{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001814 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001815
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001817 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001818 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819
1820 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1821 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001822 stream.write(mLinkedAttribute[i].type);
1823 stream.write(mLinkedAttribute[i].name);
1824 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825 }
1826
1827 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1828 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001829 stream.write(mSamplersPS[i].active);
1830 stream.write(mSamplersPS[i].logicalTextureUnit);
1831 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001832 }
1833
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001834 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001835 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001836 stream.write(mSamplersVS[i].active);
1837 stream.write(mSamplersVS[i].logicalTextureUnit);
1838 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001839 }
1840
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001841 stream.write(mUsedVertexSamplerRange);
1842 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001843 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001844 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001846 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001847 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001848 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001849 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001850
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001851 stream.write(uniform.type);
1852 stream.write(uniform.precision);
1853 stream.write(uniform.name);
1854 stream.write(uniform.arraySize);
1855 stream.write(uniform.blockIndex);
1856
1857 stream.write(uniform.blockInfo.offset);
1858 stream.write(uniform.blockInfo.arrayStride);
1859 stream.write(uniform.blockInfo.matrixStride);
1860 stream.write(uniform.blockInfo.isRowMajorMatrix);
1861
1862 stream.write(uniform.psRegisterIndex);
1863 stream.write(uniform.vsRegisterIndex);
1864 stream.write(uniform.registerCount);
1865 }
1866
1867 stream.write(mUniformBlocks.size());
1868 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1869 {
1870 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1871
1872 stream.write(uniformBlock.name);
1873 stream.write(uniformBlock.elementIndex);
1874 stream.write(uniformBlock.dataSize);
1875
1876 stream.write(uniformBlock.memberUniformIndexes.size());
1877 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1878 {
1879 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1880 }
1881
1882 stream.write(uniformBlock.psRegisterIndex);
1883 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001884 }
1885
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001886 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001887 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1888 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001889 stream.write(mUniformIndex[i].name);
1890 stream.write(mUniformIndex[i].element);
1891 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001892 }
1893
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001894 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001895 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001896
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001897 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001898 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001899
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001900 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1901 stream.write(geometryShaderSize);
1902
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001903 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001904
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001905 GLsizei streamLength = stream.length();
1906 const void *streamData = stream.data();
1907
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001908 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001909 if (totalLength > bufSize)
1910 {
1911 if (length)
1912 {
1913 *length = 0;
1914 }
1915
1916 return false;
1917 }
1918
1919 if (binary)
1920 {
1921 char *ptr = (char*) binary;
1922
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001923 memcpy(ptr, streamData, streamLength);
1924 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001925
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001926 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001927 ptr += sizeof(GUID);
1928
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001929 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001930 ptr += pixelShaderSize;
1931
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001932 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001933 ptr += vertexShaderSize;
1934
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001935 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1936 {
1937 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1938 ptr += geometryShaderSize;
1939 }
1940
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001941 ASSERT(ptr - totalLength == binary);
1942 }
1943
1944 if (length)
1945 {
1946 *length = totalLength;
1947 }
1948
1949 return true;
1950}
1951
1952GLint ProgramBinary::getLength()
1953{
1954 GLint length;
1955 if (save(NULL, INT_MAX, &length))
1956 {
1957 return length;
1958 }
1959 else
1960 {
1961 return 0;
1962 }
1963}
1964
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001965bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001966{
1967 if (!fragmentShader || !fragmentShader->isCompiled())
1968 {
1969 return false;
1970 }
1971
1972 if (!vertexShader || !vertexShader->isCompiled())
1973 {
1974 return false;
1975 }
1976
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001977 mShaderVersion = vertexShader->getShaderVersion();
1978
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001979 std::string pixelHLSL = fragmentShader->getHLSL();
1980 std::string vertexHLSL = vertexShader->getHLSL();
1981
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001982 // Map the varyings to the register file
1983 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1984 int registers = packVaryings(infoLog, packing, fragmentShader);
1985
1986 if (registers < 0)
1987 {
1988 return false;
1989 }
1990
1991 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001992 {
1993 return false;
1994 }
1995
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001996 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001997 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1998 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001999
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002000 if (usesGeometryShader())
2001 {
2002 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2003 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2004 }
2005
2006 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002007 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00002008 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002009 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00002010
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00002011 delete mVertexExecutable;
2012 mVertexExecutable = NULL;
2013 delete mPixelExecutable;
2014 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002015 delete mGeometryExecutable;
2016 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002017 }
2018
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002019 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2020 {
2021 success = false;
2022 }
2023
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002024 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002025 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002026 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002027 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002028
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002029 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2030 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2031 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002032 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2033 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2034 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 +00002035 }
2036
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002037 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2038 {
2039 success = false;
2040 }
2041
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002042 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002043}
2044
2045// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002046bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002047{
2048 unsigned int usedLocations = 0;
2049
2050 // Link attributes that have a binding location
2051 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2052 {
2053 int location = attributeBindings.getAttributeBinding(attribute->name);
2054
2055 if (location != -1) // Set by glBindAttribLocation
2056 {
2057 if (!mLinkedAttribute[location].name.empty())
2058 {
2059 // Multiple active attributes bound to the same location; not an error
2060 }
2061
2062 mLinkedAttribute[location] = *attribute;
2063
2064 int rows = VariableRowCount(attribute->type);
2065
2066 if (rows + location > MAX_VERTEX_ATTRIBS)
2067 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002068 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 +00002069
2070 return false;
2071 }
2072
2073 for (int i = 0; i < rows; i++)
2074 {
2075 usedLocations |= 1 << (location + i);
2076 }
2077 }
2078 }
2079
2080 // Link attributes that don't have a binding location
2081 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2082 {
2083 int location = attributeBindings.getAttributeBinding(attribute->name);
2084
2085 if (location == -1) // Not set by glBindAttribLocation
2086 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002087 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002088 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2089
2090 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2091 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002092 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002093
2094 return false; // Fail to link
2095 }
2096
2097 mLinkedAttribute[availableIndex] = *attribute;
2098 }
2099 }
2100
2101 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2102 {
2103 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002104 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002105
2106 for (int r = 0; r < rows; r++)
2107 {
2108 mSemanticIndex[attributeIndex++] = index++;
2109 }
2110 }
2111
2112 return true;
2113}
2114
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002115bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2116{
2117 if (vertexUniform.type != fragmentUniform.type)
2118 {
2119 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2120 return false;
2121 }
2122 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2123 {
2124 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2125 return false;
2126 }
2127 else if (vertexUniform.precision != fragmentUniform.precision)
2128 {
2129 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2130 return false;
2131 }
2132 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2133 {
2134 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2135 }
2136
2137 const unsigned int numMembers = vertexUniform.fields.size();
2138 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2139 {
2140 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2141 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2142
2143 if (vertexMember.name != fragmentMember.name)
2144 {
2145 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2146 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2147 return false;
2148 }
2149
2150 const std::string memberName = uniformName + "." + vertexUniform.name;
2151 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2152 {
2153 return false;
2154 }
2155 }
2156
2157 return true;
2158}
2159
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002160bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002161{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002162 // Check that uniforms defined in the vertex and fragment shaders are identical
2163 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2164 UniformMap linkedUniforms;
2165
2166 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2167 {
2168 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2169 linkedUniforms[vertexUniform.name] = &vertexUniform;
2170 }
2171
2172 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2173 {
2174 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2175 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2176 if (entry != linkedUniforms.end())
2177 {
2178 const sh::Uniform &vertexUniform = *entry->second;
2179 const std::string &uniformName = "uniform " + vertexUniform.name;
2180 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2181 {
2182 return false;
2183 }
2184 }
2185 }
2186
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002187 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002188 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002189 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002190 {
2191 return false;
2192 }
2193 }
2194
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002195 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002196 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002197 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002198 {
2199 return false;
2200 }
2201 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002202
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002203 return true;
2204}
2205
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002206int totalRegisterCount(const sh::Uniform &uniform)
2207{
2208 int registerCount = 0;
2209
2210 if (!uniform.fields.empty())
2211 {
2212 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2213 {
2214 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2215 }
2216 }
2217 else
2218 {
2219 registerCount = 1;
2220 }
2221
2222 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2223}
2224
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002225bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002226{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002227 if (!constant.fields.empty())
2228 {
2229 if (constant.arraySize > 0)
2230 {
2231 unsigned int elementRegisterIndex = constant.registerIndex;
2232
2233 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2234 {
2235 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2236 {
2237 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002238 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002239 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2240 if (!defineUniform(shader, fieldUniform, infoLog))
2241 {
2242 return false;
2243 }
2244 elementRegisterIndex += totalRegisterCount(field);
2245 }
2246 }
2247 }
2248 else
2249 {
2250 unsigned int fieldRegisterIndex = constant.registerIndex;
2251
2252 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2253 {
2254 const sh::Uniform &field = constant.fields[fieldIndex];
2255 const std::string &uniformName = constant.name + "." + field.name;
2256
2257 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2258 fieldUniform.fields = field.fields;
2259
2260 if (!defineUniform(shader, fieldUniform, infoLog))
2261 {
2262 return false;
2263 }
2264 fieldRegisterIndex += totalRegisterCount(field);
2265 }
2266 }
2267
2268 return true;
2269 }
2270
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002271 if (constant.type == GL_SAMPLER_2D ||
2272 constant.type == GL_SAMPLER_CUBE)
2273 {
2274 unsigned int samplerIndex = constant.registerIndex;
2275
2276 do
2277 {
2278 if (shader == GL_VERTEX_SHADER)
2279 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002280 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002281 {
2282 mSamplersVS[samplerIndex].active = true;
2283 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2284 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2285 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2286 }
2287 else
2288 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002289 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002290 return false;
2291 }
2292 }
2293 else if (shader == GL_FRAGMENT_SHADER)
2294 {
2295 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2296 {
2297 mSamplersPS[samplerIndex].active = true;
2298 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2299 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2300 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2301 }
2302 else
2303 {
2304 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2305 return false;
2306 }
2307 }
2308 else UNREACHABLE();
2309
2310 samplerIndex++;
2311 }
2312 while (samplerIndex < constant.registerIndex + constant.arraySize);
2313 }
2314
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002315 Uniform *uniform = NULL;
2316 GLint location = getUniformLocation(constant.name);
2317
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002318 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002319 {
2320 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002321 }
2322 else
2323 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002324 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002325 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002326
2327 if (!uniform)
2328 {
2329 return false;
2330 }
2331
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002332 if (shader == GL_FRAGMENT_SHADER)
2333 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002334 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002335 }
2336 else if (shader == GL_VERTEX_SHADER)
2337 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002338 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002339 }
2340 else UNREACHABLE();
2341
2342 if (location >= 0)
2343 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002344 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002345 }
2346
2347 mUniforms.push_back(uniform);
2348 unsigned int uniformIndex = mUniforms.size() - 1;
2349
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002350 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002351 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002352 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002353 }
2354
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002355 if (shader == GL_VERTEX_SHADER)
2356 {
2357 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2358 {
2359 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2360 return false;
2361 }
2362 }
2363 else if (shader == GL_FRAGMENT_SHADER)
2364 {
2365 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2366 {
2367 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2368 return false;
2369 }
2370 }
2371 else UNREACHABLE();
2372
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002373 return true;
2374}
2375
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002376bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2377{
2378 const char* blockName = vertexInterfaceBlock.name.c_str();
2379
2380 // validate blocks for the same member types
2381 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2382 {
2383 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2384 return false;
2385 }
2386
2387 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2388 {
2389 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2390 return false;
2391 }
2392
2393 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2394 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2395 {
2396 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2397 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2398
2399 if (vertexMember.name != fragmentMember.name)
2400 {
2401 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2402 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2403 return false;
2404 }
2405
2406 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2407 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2408 {
2409 return false;
2410 }
2411 }
2412
2413 return true;
2414}
2415
2416bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2417{
2418 // Check that interface blocks defined in the vertex and fragment shaders are identical
2419 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2420 UniformBlockMap linkedUniformBlocks;
2421
2422 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2423 {
2424 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2425 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2426 }
2427
2428 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2429 {
2430 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2431 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2432 if (entry != linkedUniformBlocks.end())
2433 {
2434 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2435 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2436 {
2437 return false;
2438 }
2439 }
2440 }
2441
2442 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2443 {
2444 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2445 {
2446 return false;
2447 }
2448 }
2449
2450 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2451 {
2452 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2453 {
2454 return false;
2455 }
2456 }
2457
2458 return true;
2459}
2460
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002461void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2462{
2463 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2464 {
2465 const sh::Uniform &uniform = uniforms[uniformIndex];
Jamie Madillacdd70f2013-06-07 14:39:56 -04002466 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002467
2468 if (!uniform.fields.empty())
2469 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002470 if (uniform.arraySize > 0)
2471 {
2472 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2473 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002474 const std::string uniformElementName = uniformName + arrayString(arrayElement);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002475 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2476 }
2477 }
2478 else
2479 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002480 defineUniformBlockMembers(uniform.fields, uniformName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002481 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002482 }
2483 else
2484 {
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002485 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2486 blockIndex, **blockInfoItr);
2487
2488 // add to uniform list, but not index, since uniform block uniforms have no location
2489 blockUniformIndexes->push_back(mUniforms.size());
2490 mUniforms.push_back(newUniform);
2491 (*blockInfoItr)++;
2492 }
2493 }
2494}
2495
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002496bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2497{
2498 // create uniform block entries if they do not exist
2499 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2500 {
2501 std::vector<unsigned int> blockUniformIndexes;
2502 const unsigned int blockIndex = mUniformBlocks.size();
2503
2504 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002505 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2506 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002507
2508 // create all the uniform blocks
2509 if (interfaceBlock.arraySize > 0)
2510 {
2511 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2512 {
2513 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2514 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2515 mUniformBlocks.push_back(newUniformBlock);
2516 }
2517 }
2518 else
2519 {
2520 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2521 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2522 mUniformBlocks.push_back(newUniformBlock);
2523 }
2524 }
2525
2526 // Assign registers to the uniform blocks
2527 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2528 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2529 ASSERT(blockIndex != GL_INVALID_INDEX);
2530 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2531
2532 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2533 {
2534 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2535 ASSERT(uniformBlock->name == interfaceBlock.name);
2536
2537 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2538 {
2539 return false;
2540 }
2541 }
2542
2543 return true;
2544}
2545
2546bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2547{
2548 if (shader == GL_VERTEX_SHADER)
2549 {
2550 uniformBlock->vsRegisterIndex = registerIndex;
2551 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2552
2553 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2554 {
2555 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2556 return false;
2557 }
2558 }
2559 else if (shader == GL_FRAGMENT_SHADER)
2560 {
2561 uniformBlock->psRegisterIndex = registerIndex;
2562 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2563
2564 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2565 {
2566 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2567 return false;
2568 }
2569 }
2570 else UNREACHABLE();
2571
2572 return true;
2573}
2574
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002575std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2576{
2577 // for now we only handle point sprite emulation
2578 ASSERT(usesPointSpriteEmulation());
2579 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2580}
2581
2582std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2583{
2584 ASSERT(registers >= 0);
2585 ASSERT(vertexShader->mUsesPointSize);
2586 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2587
2588 std::string geomHLSL;
2589
2590 std::string varyingSemantic = "TEXCOORD";
2591
2592 std::string fragCoordSemantic;
2593 std::string pointCoordSemantic;
2594
2595 int reservedRegisterIndex = registers;
2596
2597 if (fragmentShader->mUsesFragCoord)
2598 {
2599 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2600 }
2601
2602 if (fragmentShader->mUsesPointCoord)
2603 {
2604 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2605 }
2606
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002607 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2608 "\n"
2609 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002610 "{\n";
2611
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002612 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002613
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002614 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002615
2616 if (fragmentShader->mUsesFragCoord)
2617 {
2618 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2619 }
2620
2621 geomHLSL += " float gl_PointSize : PSIZE;\n"
2622 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002623 "};\n"
2624 "\n"
2625 "struct GS_OUTPUT\n"
2626 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002627
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002628 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002629
2630 if (fragmentShader->mUsesFragCoord)
2631 {
2632 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2633 }
2634
2635 if (fragmentShader->mUsesPointCoord)
2636 {
2637 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2638 }
2639
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002640 geomHLSL += " float gl_PointSize : PSIZE;\n"
2641 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002642 "};\n"
2643 "\n"
2644 "static float2 pointSpriteCorners[] = \n"
2645 "{\n"
2646 " float2( 0.5f, -0.5f),\n"
2647 " float2( 0.5f, 0.5f),\n"
2648 " float2(-0.5f, -0.5f),\n"
2649 " float2(-0.5f, 0.5f)\n"
2650 "};\n"
2651 "\n"
2652 "static float2 pointSpriteTexcoords[] = \n"
2653 "{\n"
2654 " float2(1.0f, 1.0f),\n"
2655 " float2(1.0f, 0.0f),\n"
2656 " float2(0.0f, 1.0f),\n"
2657 " float2(0.0f, 0.0f)\n"
2658 "};\n"
2659 "\n"
2660 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2661 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2662 "\n"
2663 "[maxvertexcount(4)]\n"
2664 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2665 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002666 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2667 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002668
2669 for (int r = 0; r < registers; r++)
2670 {
2671 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2672 }
2673
2674 if (fragmentShader->mUsesFragCoord)
2675 {
2676 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2677 }
2678
2679 geomHLSL += " \n"
2680 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2681 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002682 " 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 +00002683
2684 for (int corner = 0; corner < 4; corner++)
2685 {
2686 geomHLSL += " \n"
2687 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2688
2689 if (fragmentShader->mUsesPointCoord)
2690 {
2691 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2692 }
2693
2694 geomHLSL += " outStream.Append(output);\n";
2695 }
2696
2697 geomHLSL += " \n"
2698 " outStream.RestartStrip();\n"
2699 "}\n";
2700
2701 return geomHLSL;
2702}
2703
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002704// This method needs to match OutputHLSL::decorate
2705std::string ProgramBinary::decorateAttribute(const std::string &name)
2706{
2707 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2708 {
2709 return "_" + name;
2710 }
2711
2712 return name;
2713}
2714
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002715bool ProgramBinary::isValidated() const
2716{
2717 return mValidated;
2718}
2719
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002720void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002721{
2722 // Skip over inactive attributes
2723 unsigned int activeAttribute = 0;
2724 unsigned int attribute;
2725 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2726 {
2727 if (mLinkedAttribute[attribute].name.empty())
2728 {
2729 continue;
2730 }
2731
2732 if (activeAttribute == index)
2733 {
2734 break;
2735 }
2736
2737 activeAttribute++;
2738 }
2739
2740 if (bufsize > 0)
2741 {
2742 const char *string = mLinkedAttribute[attribute].name.c_str();
2743
2744 strncpy(name, string, bufsize);
2745 name[bufsize - 1] = '\0';
2746
2747 if (length)
2748 {
2749 *length = strlen(name);
2750 }
2751 }
2752
2753 *size = 1; // Always a single 'type' instance
2754
2755 *type = mLinkedAttribute[attribute].type;
2756}
2757
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002758GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002759{
2760 int count = 0;
2761
2762 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2763 {
2764 if (!mLinkedAttribute[attributeIndex].name.empty())
2765 {
2766 count++;
2767 }
2768 }
2769
2770 return count;
2771}
2772
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002773GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002774{
2775 int maxLength = 0;
2776
2777 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2778 {
2779 if (!mLinkedAttribute[attributeIndex].name.empty())
2780 {
2781 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2782 }
2783 }
2784
2785 return maxLength;
2786}
2787
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002788void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002789{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002790 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002791
2792 if (bufsize > 0)
2793 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002794 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002795
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002796 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002797 {
2798 string += "[0]";
2799 }
2800
2801 strncpy(name, string.c_str(), bufsize);
2802 name[bufsize - 1] = '\0';
2803
2804 if (length)
2805 {
2806 *length = strlen(name);
2807 }
2808 }
2809
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002810 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002811
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002812 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002813}
2814
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002815GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002816{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002817 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002818}
2819
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002820GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002821{
2822 int maxLength = 0;
2823
2824 unsigned int numUniforms = mUniforms.size();
2825 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2826 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002827 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002828 {
2829 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2830 if (mUniforms[uniformIndex]->isArray())
2831 {
2832 length += 3; // Counting in "[0]".
2833 }
2834 maxLength = std::max(length, maxLength);
2835 }
2836 }
2837
2838 return maxLength;
2839}
2840
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002841GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2842{
2843 const gl::Uniform& uniform = *mUniforms[index];
2844
2845 switch (pname)
2846 {
2847 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2848 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002849 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 +00002850 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002851
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002852 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2853 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2854 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2855 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002856
2857 default:
2858 UNREACHABLE();
2859 break;
2860 }
2861 return 0;
2862}
2863
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002864void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2865{
2866 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2867
2868 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2869
2870 if (bufSize > 0)
2871 {
2872 std::string string = uniformBlock.name;
2873
2874 if (uniformBlock.isArrayElement())
2875 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002876 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002877 }
2878
2879 strncpy(uniformBlockName, string.c_str(), bufSize);
2880 uniformBlockName[bufSize - 1] = '\0';
2881
2882 if (length)
2883 {
2884 *length = strlen(uniformBlockName);
2885 }
2886 }
2887}
2888
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002889void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2890{
2891 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2892
2893 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2894
2895 switch (pname)
2896 {
2897 case GL_UNIFORM_BLOCK_DATA_SIZE:
2898 *params = static_cast<GLint>(uniformBlock.dataSize);
2899 break;
2900 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002901 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002902 break;
2903 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2904 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2905 break;
2906 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2907 {
2908 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2909 {
2910 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2911 }
2912 }
2913 break;
2914 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2915 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2916 break;
2917 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2918 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2919 break;
2920 default: UNREACHABLE();
2921 }
2922}
2923
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002924GLuint ProgramBinary::getActiveUniformBlockCount() const
2925{
2926 return mUniformBlocks.size();
2927}
2928
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002929GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2930{
2931 unsigned int maxLength = 0;
2932
2933 unsigned int numUniformBlocks = mUniformBlocks.size();
2934 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2935 {
2936 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2937 if (!uniformBlock.name.empty())
2938 {
2939 const unsigned int length = uniformBlock.name.length() + 1;
2940
2941 // Counting in "[0]".
2942 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2943
2944 maxLength = std::max(length + arrayLength, maxLength);
2945 }
2946 }
2947
2948 return maxLength;
2949}
2950
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002951void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002952{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002953 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002954 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002955 {
2956 mValidated = false;
2957 }
2958 else
2959 {
2960 mValidated = true;
2961 }
2962}
2963
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002964bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002965{
2966 // if any two active samplers in a program are of different types, but refer to the same
2967 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2968 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2969
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002970 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002971 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002972
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002973 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002974 {
2975 textureUnitType[i] = TEXTURE_UNKNOWN;
2976 }
2977
2978 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2979 {
2980 if (mSamplersPS[i].active)
2981 {
2982 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2983
2984 if (unit >= maxCombinedTextureImageUnits)
2985 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002986 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002987 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002988 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002989 }
2990
2991 return false;
2992 }
2993
2994 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2995 {
2996 if (mSamplersPS[i].textureType != textureUnitType[unit])
2997 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002998 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002999 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003000 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003001 }
3002
3003 return false;
3004 }
3005 }
3006 else
3007 {
3008 textureUnitType[unit] = mSamplersPS[i].textureType;
3009 }
3010 }
3011 }
3012
3013 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3014 {
3015 if (mSamplersVS[i].active)
3016 {
3017 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3018
3019 if (unit >= maxCombinedTextureImageUnits)
3020 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003021 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003022 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003023 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003024 }
3025
3026 return false;
3027 }
3028
3029 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3030 {
3031 if (mSamplersVS[i].textureType != textureUnitType[unit])
3032 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003033 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003034 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003035 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003036 }
3037
3038 return false;
3039 }
3040 }
3041 else
3042 {
3043 textureUnitType[unit] = mSamplersVS[i].textureType;
3044 }
3045 }
3046 }
3047
3048 return true;
3049}
3050
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003051ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3052{
3053}
3054
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003055struct AttributeSorter
3056{
3057 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3058 : originalIndices(semanticIndices)
3059 {
3060 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3061 {
3062 indices[i] = i;
3063 }
3064
3065 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3066 }
3067
3068 bool operator()(int a, int b)
3069 {
3070 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3071 }
3072
3073 int indices[MAX_VERTEX_ATTRIBS];
3074 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3075};
3076
3077void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3078{
3079 AttributeSorter sorter(mSemanticIndex);
3080
3081 int oldIndices[MAX_VERTEX_ATTRIBS];
3082 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3083
3084 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3085 {
3086 oldIndices[i] = mSemanticIndex[i];
3087 oldTranslatedAttributes[i] = attributes[i];
3088 }
3089
3090 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3091 {
3092 int oldIndex = sorter.indices[i];
3093 sortedSemanticIndices[i] = oldIndices[oldIndex];
3094 attributes[i] = oldTranslatedAttributes[oldIndex];
3095 }
3096}
3097
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003098}