blob: 7ce0783ac49e058761939688058fb69ebce6f23d [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
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000044namespace gl_d3d
45{
46 std::string TypeString(GLenum type)
47 {
48 switch (type)
49 {
50 case GL_FLOAT: return "float";
51 case GL_FLOAT_VEC2: return "float2";
52 case GL_FLOAT_VEC3: return "float3";
53 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000054 case GL_INT: return "int";
55 case GL_INT_VEC2: return "int2";
56 case GL_INT_VEC3: return "int3";
57 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000058 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000059 case GL_UNSIGNED_INT_VEC2: return "uint2";
60 case GL_UNSIGNED_INT_VEC3: return "uint3";
61 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000062 case GL_FLOAT_MAT2: return "float2x2";
63 case GL_FLOAT_MAT3: return "float3x3";
64 case GL_FLOAT_MAT4: return "float4x4";
65 case GL_FLOAT_MAT2x3: return "float2x3";
66 case GL_FLOAT_MAT3x2: return "float3x2";
67 case GL_FLOAT_MAT2x4: return "float2x4";
68 case GL_FLOAT_MAT4x2: return "float4x2";
69 case GL_FLOAT_MAT3x4: return "float3x4";
70 case GL_FLOAT_MAT4x3: return "float4x3";
71 default: UNREACHABLE(); return "invalid-gl-type";
72 }
73 }
74}
75
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000076namespace
77{
78
79unsigned int parseAndStripArrayIndex(std::string* name)
80{
81 unsigned int subscript = GL_INVALID_INDEX;
82
83 // Strip any trailing array operator and retrieve the subscript
84 size_t open = name->find_last_of('[');
85 size_t close = name->find_last_of(']');
86 if (open != std::string::npos && close == name->length() - 1)
87 {
88 subscript = atoi(name->substr(open + 1).c_str());
89 name->erase(open);
90 }
91
92 return subscript;
93}
94
95}
96
Jamie Madill63491ea2013-06-06 11:56:45 -040097VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +000098 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000099{
100}
101
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000102unsigned int ProgramBinary::mCurrentSerial = 1;
103
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000104ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000105{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106 mPixelExecutable = NULL;
107 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000108 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000109
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000110 mValidated = false;
111
112 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
113 {
114 mSemanticIndex[index] = -1;
115 }
116
117 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
118 {
119 mSamplersPS[index].active = false;
120 }
121
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000122 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000123 {
124 mSamplersVS[index].active = false;
125 }
126
127 mUsedVertexSamplerRange = 0;
128 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000129 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000130 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000131}
132
133ProgramBinary::~ProgramBinary()
134{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000135 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000136 mPixelExecutable = NULL;
137
daniel@transgaming.com95892412012-11-28 20:59:09 +0000138 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000139 mVertexExecutable = NULL;
140
141 delete mGeometryExecutable;
142 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000143
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000144 while (!mUniforms.empty())
145 {
146 delete mUniforms.back();
147 mUniforms.pop_back();
148 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000149
150 while (!mUniformBlocks.empty())
151 {
152 delete mUniformBlocks.back();
153 mUniformBlocks.pop_back();
154 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000155}
156
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000157unsigned int ProgramBinary::getSerial() const
158{
159 return mSerial;
160}
161
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000162int ProgramBinary::getShaderVersion() const
163{
164 return mShaderVersion;
165}
166
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000167unsigned int ProgramBinary::issueSerial()
168{
169 return mCurrentSerial++;
170}
171
daniel@transgaming.com95892412012-11-28 20:59:09 +0000172rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000173{
174 return mPixelExecutable;
175}
176
daniel@transgaming.com95892412012-11-28 20:59:09 +0000177rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000178{
179 return mVertexExecutable;
180}
181
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000182rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
183{
184 return mGeometryExecutable;
185}
186
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000187GLuint ProgramBinary::getAttributeLocation(const char *name)
188{
189 if (name)
190 {
191 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
192 {
193 if (mLinkedAttribute[index].name == std::string(name))
194 {
195 return index;
196 }
197 }
198 }
199
200 return -1;
201}
202
203int ProgramBinary::getSemanticIndex(int attributeIndex)
204{
205 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
206
207 return mSemanticIndex[attributeIndex];
208}
209
210// Returns one more than the highest sampler index used.
211GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
212{
213 switch (type)
214 {
215 case SAMPLER_PIXEL:
216 return mUsedPixelSamplerRange;
217 case SAMPLER_VERTEX:
218 return mUsedVertexSamplerRange;
219 default:
220 UNREACHABLE();
221 return 0;
222 }
223}
224
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000225bool ProgramBinary::usesPointSize() const
226{
227 return mUsesPointSize;
228}
229
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000230bool ProgramBinary::usesPointSpriteEmulation() const
231{
232 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
233}
234
235bool ProgramBinary::usesGeometryShader() const
236{
237 return usesPointSpriteEmulation();
238}
239
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000240// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
241// index (0-15 for the pixel shader and 0-3 for the vertex shader).
242GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
243{
244 GLint logicalTextureUnit = -1;
245
246 switch (type)
247 {
248 case SAMPLER_PIXEL:
249 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
250
251 if (mSamplersPS[samplerIndex].active)
252 {
253 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
254 }
255 break;
256 case SAMPLER_VERTEX:
257 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
258
259 if (mSamplersVS[samplerIndex].active)
260 {
261 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
262 }
263 break;
264 default: UNREACHABLE();
265 }
266
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000267 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000268 {
269 return logicalTextureUnit;
270 }
271
272 return -1;
273}
274
275// Returns the texture type for a given Direct3D 9 sampler type and
276// index (0-15 for the pixel shader and 0-3 for the vertex shader).
277TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
278{
279 switch (type)
280 {
281 case SAMPLER_PIXEL:
282 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
283 ASSERT(mSamplersPS[samplerIndex].active);
284 return mSamplersPS[samplerIndex].textureType;
285 case SAMPLER_VERTEX:
286 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
287 ASSERT(mSamplersVS[samplerIndex].active);
288 return mSamplersVS[samplerIndex].textureType;
289 default: UNREACHABLE();
290 }
291
292 return TEXTURE_2D;
293}
294
295GLint ProgramBinary::getUniformLocation(std::string name)
296{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000297 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000298
299 unsigned int numUniforms = mUniformIndex.size();
300 for (unsigned int location = 0; location < numUniforms; location++)
301 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000302 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000303 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000304 const int index = mUniformIndex[location].index;
305 const bool isArray = mUniforms[index]->isArray();
306
307 if ((isArray && mUniformIndex[location].element == subscript) ||
308 (subscript == GL_INVALID_INDEX))
309 {
310 return location;
311 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000312 }
313 }
314
315 return -1;
316}
317
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000318GLuint ProgramBinary::getUniformIndex(std::string name)
319{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000320 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000321
322 // The app is not allowed to specify array indices other than 0 for arrays of basic types
323 if (subscript != 0 && subscript != GL_INVALID_INDEX)
324 {
325 return GL_INVALID_INDEX;
326 }
327
328 unsigned int numUniforms = mUniforms.size();
329 for (unsigned int index = 0; index < numUniforms; index++)
330 {
331 if (mUniforms[index]->name == name)
332 {
333 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
334 {
335 return index;
336 }
337 }
338 }
339
340 return GL_INVALID_INDEX;
341}
342
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000343GLuint ProgramBinary::getUniformBlockIndex(std::string name)
344{
345 unsigned int subscript = parseAndStripArrayIndex(&name);
346
347 unsigned int numUniformBlocks = mUniformBlocks.size();
348 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
349 {
350 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
351 if (uniformBlock.name == name)
352 {
353 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
354 if (subscript == uniformBlock.elementIndex || arrayElementZero)
355 {
356 return blockIndex;
357 }
358 }
359 }
360
361 return GL_INVALID_INDEX;
362}
363
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000364UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
365{
366 ASSERT(blockIndex < mUniformBlocks.size());
367 return mUniformBlocks[blockIndex];
368}
369
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000370template <typename T>
371bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372{
373 if (location < 0 || location >= (int)mUniformIndex.size())
374 {
375 return false;
376 }
377
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000378 const int components = UniformComponentCount(targetUniformType);
379 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
380
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000381 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
382 targetUniform->dirty = true;
383
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000384 int elementCount = targetUniform->elementCount();
385
386 if (elementCount == 1 && count > 1)
387 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
388
389 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
390
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000391 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000393 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394
395 for (int i = 0; i < count; i++)
396 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000397 for (int c = 0; c < components; c++)
398 {
399 target[c] = v[c];
400 }
401 for (int c = components; c < 4; c++)
402 {
403 target[c] = 0;
404 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000406 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000407 }
408 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000409 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000410 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000411 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000413 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000414 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000415 for (int c = 0; c < components; c++)
416 {
417 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
418 }
419 for (int c = components; c < 4; c++)
420 {
421 boolParams[c] = GL_FALSE;
422 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000423 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000424 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000425 }
426 }
427 else
428 {
429 return false;
430 }
431
432 return true;
433}
434
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000435bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
436{
437 return setUniform(location, count, v, GL_FLOAT);
438}
439
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000440bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
441{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000442 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000443}
444
445bool ProgramBinary::setUniform3fv(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_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448}
449
450bool ProgramBinary::setUniform4fv(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_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000453}
454
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000455template<typename T>
456void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000457{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000458 int copyWidth = std::min(targetHeight, srcWidth);
459 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000460
461 for (int x = 0; x < copyWidth; x++)
462 {
463 for (int y = 0; y < copyHeight; y++)
464 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000465 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000466 }
467 }
468 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000469 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000470 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000471 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000472 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000473 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000474 }
475 }
476 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000477 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000478 {
479 for (int x = 0; x < targetWidth; x++)
480 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000481 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000482 }
483 }
484}
485
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000486template<typename T>
487void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
488{
489 int copyWidth = std::min(targetWidth, srcWidth);
490 int copyHeight = std::min(targetHeight, srcHeight);
491
492 for (int y = 0; y < copyHeight; y++)
493 {
494 for (int x = 0; x < copyWidth; x++)
495 {
496 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
497 }
498 }
499 // clear unfilled right side
500 for (int y = 0; y < copyHeight; y++)
501 {
502 for (int x = copyWidth; x < targetWidth; x++)
503 {
504 target[y * targetWidth + x] = static_cast<T>(0);
505 }
506 }
507 // clear unfilled bottom.
508 for (int y = copyHeight; y < targetHeight; y++)
509 {
510 for (int x = 0; x < targetWidth; x++)
511 {
512 target[y * targetWidth + x] = static_cast<T>(0);
513 }
514 }
515}
516
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000517template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000518bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000519{
520 if (location < 0 || location >= (int)mUniformIndex.size())
521 {
522 return false;
523 }
524
525 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
526 targetUniform->dirty = true;
527
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000528 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529 {
530 return false;
531 }
532
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000533 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000534
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000535 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000536 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
537
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000538 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000539 const unsigned int targetMatrixStride = (4 * rows);
540 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000541
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542 for (int i = 0; i < count; i++)
543 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000544 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
545 if (transpose == GL_FALSE)
546 {
547 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
548 }
549 else
550 {
551 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
552 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000553 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000554 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555 }
556
557 return true;
558}
559
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000560bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000561{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000562 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000563}
564
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000565bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000566{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568}
569
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000570bool ProgramBinary::setUniformMatrix4fv(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<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000573}
574
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000575bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000576{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000577 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000578}
579
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000580bool ProgramBinary::setUniformMatrix3x2fv(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<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
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::setUniformMatrix2x4fv(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<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
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::setUniformMatrix4x2fv(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<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
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::setUniformMatrix3x4fv(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<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
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::setUniformMatrix4x3fv(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<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000603}
604
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000605bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
606{
607 if (location < 0 || location >= (int)mUniformIndex.size())
608 {
609 return false;
610 }
611
612 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
613 targetUniform->dirty = true;
614
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000615 int elementCount = targetUniform->elementCount();
616
617 if (elementCount == 1 && count > 1)
618 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
619
620 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
621
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000622 if (targetUniform->type == GL_INT ||
623 targetUniform->type == GL_SAMPLER_2D ||
624 targetUniform->type == GL_SAMPLER_CUBE)
625 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000626 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000627
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000628 for (int i = 0; i < count; i++)
629 {
630 target[0] = v[0];
631 target[1] = 0;
632 target[2] = 0;
633 target[3] = 0;
634 target += 4;
635 v += 1;
636 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000637 }
638 else if (targetUniform->type == GL_BOOL)
639 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000640 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000641
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000642 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000643 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000644 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
645 boolParams[1] = GL_FALSE;
646 boolParams[2] = GL_FALSE;
647 boolParams[3] = GL_FALSE;
648 boolParams += 4;
649 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000650 }
651 }
652 else
653 {
654 return false;
655 }
656
657 return true;
658}
659
660bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
661{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000662 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000663}
664
665bool ProgramBinary::setUniform3iv(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_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668}
669
670bool ProgramBinary::setUniform4iv(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_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000673}
674
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000675bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
676{
677 return setUniform(location, count, v, GL_UNSIGNED_INT);
678}
679
680bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
681{
682 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
683}
684
685bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
686{
687 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
688}
689
690bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
691{
692 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
693}
694
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000695template <typename T>
696bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697{
698 if (location < 0 || location >= (int)mUniformIndex.size())
699 {
700 return false;
701 }
702
703 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
704
705 // sized queries -- ensure the provided buffer is large enough
706 if (bufSize)
707 {
708 int requiredBytes = UniformExternalSize(targetUniform->type);
709 if (*bufSize < requiredBytes)
710 {
711 return false;
712 }
713 }
714
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000715 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000716 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000717 const int rows = VariableRowCount(targetUniform->type);
718 const int cols = VariableColumnCount(targetUniform->type);
719 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
720 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000721 else if (uniformType == UniformComponentType(targetUniform->type))
722 {
723 unsigned int size = UniformComponentCount(targetUniform->type);
724 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
725 size * sizeof(T));
726 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000727 else
728 {
729 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000730 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000731 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000732 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000734 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000735
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000736 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000737 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000738 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000739 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000740 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000741 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000742
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000743 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000744 {
745 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
746
747 for (unsigned int i = 0; i < size; i++)
748 {
749 params[i] = static_cast<T>(floatParams[i]);
750 }
751 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000752 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000753
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000754 case GL_INT:
755 {
756 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
757
758 for (unsigned int i = 0; i < size; i++)
759 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000760 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000761 }
762 }
763 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000764
765 case GL_UNSIGNED_INT:
766 {
767 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000768
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000769 for (unsigned int i = 0; i < size; i++)
770 {
771 params[i] = static_cast<T>(uintParams[i]);
772 }
773 }
774 break;
775
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000776 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000777 }
778 }
779
780 return true;
781}
782
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000783bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
784{
785 return getUniformv(location, bufSize, params, GL_FLOAT);
786}
787
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000788bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
789{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000790 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000791}
792
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000793bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
794{
795 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
796}
797
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000798void ProgramBinary::dirtyAllUniforms()
799{
800 unsigned int numUniforms = mUniforms.size();
801 for (unsigned int index = 0; index < numUniforms; index++)
802 {
803 mUniforms[index]->dirty = true;
804 }
805}
806
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000807// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000808void ProgramBinary::applyUniforms()
809{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000810 // Retrieve sampler uniform values
811 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
812 {
813 Uniform *targetUniform = *ub;
814
815 if (targetUniform->dirty)
816 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000817 if (targetUniform->type == GL_SAMPLER_2D ||
818 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000819 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000820 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000821 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000822
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000823 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000824 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000825 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000826
827 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000828 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000829 unsigned int samplerIndex = firstIndex + i;
830
831 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000832 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000833 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000834 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000835 }
836 }
837 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000838
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000839 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000840 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000841 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000842
843 for (int i = 0; i < count; i++)
844 {
845 unsigned int samplerIndex = firstIndex + i;
846
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000847 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000848 {
849 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000850 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000851 }
852 }
853 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000854 }
855 }
856 }
857
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000858 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000859}
860
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000861bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
862{
863 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
864 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
865
866 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
867 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
868
869 ASSERT(boundBuffers.size() == mUniformBlocks.size());
870
871 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
872 {
873 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
874 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
875
876 ASSERT(uniformBlock && uniformBuffer);
877
878 if (uniformBuffer->size() < uniformBlock->dataSize)
879 {
880 // undefined behaviour
881 return false;
882 }
883
884 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
885
886 if (uniformBlock->isReferencedByVertexShader())
887 {
888 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
889 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
890 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
891 vertexUniformBuffers[registerIndex] = uniformBuffer;
892 }
893
894 if (uniformBlock->isReferencedByFragmentShader())
895 {
896 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
897 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
898 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
899 fragmentUniformBuffers[registerIndex] = uniformBuffer;
900 }
901 }
902
903 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
904}
905
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000906// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
907// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000908int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000909{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000910 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000911
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000912 fragmentShader->resetVaryingsRegisterAssignment();
913
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000914 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
915 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000916 GLenum transposedType = TransposeMatrixType(varying->type);
917 int n = VariableRowCount(transposedType) * varying->size;
918 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000919 bool success = false;
920
921 if (m == 2 || m == 3 || m == 4)
922 {
923 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
924 {
925 bool available = true;
926
927 for (int y = 0; y < n && available; y++)
928 {
929 for (int x = 0; x < m && available; x++)
930 {
931 if (packing[r + y][x])
932 {
933 available = false;
934 }
935 }
936 }
937
938 if (available)
939 {
940 varying->reg = r;
941 varying->col = 0;
942
943 for (int y = 0; y < n; y++)
944 {
945 for (int x = 0; x < m; x++)
946 {
947 packing[r + y][x] = &*varying;
948 }
949 }
950
951 success = true;
952 }
953 }
954
955 if (!success && m == 2)
956 {
957 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
958 {
959 bool available = true;
960
961 for (int y = 0; y < n && available; y++)
962 {
963 for (int x = 2; x < 4 && available; x++)
964 {
965 if (packing[r + y][x])
966 {
967 available = false;
968 }
969 }
970 }
971
972 if (available)
973 {
974 varying->reg = r;
975 varying->col = 2;
976
977 for (int y = 0; y < n; y++)
978 {
979 for (int x = 2; x < 4; x++)
980 {
981 packing[r + y][x] = &*varying;
982 }
983 }
984
985 success = true;
986 }
987 }
988 }
989 }
990 else if (m == 1)
991 {
992 int space[4] = {0};
993
994 for (int y = 0; y < maxVaryingVectors; y++)
995 {
996 for (int x = 0; x < 4; x++)
997 {
998 space[x] += packing[y][x] ? 0 : 1;
999 }
1000 }
1001
1002 int column = 0;
1003
1004 for (int x = 0; x < 4; x++)
1005 {
1006 if (space[x] >= n && space[x] < space[column])
1007 {
1008 column = x;
1009 }
1010 }
1011
1012 if (space[column] >= n)
1013 {
1014 for (int r = 0; r < maxVaryingVectors; r++)
1015 {
1016 if (!packing[r][column])
1017 {
1018 varying->reg = r;
1019
1020 for (int y = r; y < r + n; y++)
1021 {
1022 packing[y][column] = &*varying;
1023 }
1024
1025 break;
1026 }
1027 }
1028
1029 varying->col = column;
1030
1031 success = true;
1032 }
1033 }
1034 else UNREACHABLE();
1035
1036 if (!success)
1037 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001038 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001039
1040 return -1;
1041 }
1042 }
1043
1044 // Return the number of used registers
1045 int registers = 0;
1046
1047 for (int r = 0; r < maxVaryingVectors; r++)
1048 {
1049 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1050 {
1051 registers++;
1052 }
1053 }
1054
1055 return registers;
1056}
1057
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001058bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1059 std::string& pixelHLSL, std::string& vertexHLSL,
1060 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001061{
1062 if (pixelHLSL.empty() || vertexHLSL.empty())
1063 {
1064 return false;
1065 }
1066
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001067 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1068 bool usesFragColor = fragmentShader->mUsesFragColor;
1069 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001070 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001071 {
1072 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1073 return false;
1074 }
1075
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001076 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001077 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001078 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001079
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001080 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1081
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001082 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1083 // - with a 3.0 context, the output color is copied to channel 0
1084 // - with a 2.0 context, the output color is broadcast to all channels
1085 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1086 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1087
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001088 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001089 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001090 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001091
1092 return false;
1093 }
1094
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001095 vertexShader->resetVaryingsRegisterAssignment();
1096
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001097 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1098 {
1099 bool matched = false;
1100
1101 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1102 {
1103 if (output->name == input->name)
1104 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001105 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001106 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001107 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 +00001108
1109 return false;
1110 }
1111
1112 output->reg = input->reg;
1113 output->col = input->col;
1114
1115 matched = true;
1116 break;
1117 }
1118 }
1119
1120 if (!matched)
1121 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001122 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001123
1124 return false;
1125 }
1126 }
1127
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001128 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001129 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001130 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001131 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1132
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001133 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1134
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001135 // special varyings that use reserved registers
1136 int reservedRegisterIndex = registers;
1137 std::string fragCoordSemantic;
1138 std::string pointCoordSemantic;
1139
1140 if (fragmentShader->mUsesFragCoord)
1141 {
1142 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1143 }
1144
1145 if (fragmentShader->mUsesPointCoord)
1146 {
1147 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1148 // In DX11 we compute this in the GS.
1149 if (shaderModel == 3)
1150 {
1151 pointCoordSemantic = "TEXCOORD0";
1152 }
1153 else if (shaderModel >= 4)
1154 {
1155 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1156 }
1157 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001158
1159 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001160 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001161
1162 int semanticIndex = 0;
1163 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1164 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001165 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001166 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1167
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001168 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001169 }
1170
1171 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001172 "\n"
1173 "struct VS_OUTPUT\n"
1174 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001176 if (shaderModel < 4)
1177 {
1178 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1179 }
1180
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001181 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001182
1183 if (fragmentShader->mUsesFragCoord)
1184 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001185 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001186 }
1187
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001188 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001189 {
1190 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1191 }
1192
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001193 if (shaderModel >= 4)
1194 {
1195 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1196 }
1197
1198 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001199 "\n"
1200 "VS_OUTPUT main(VS_INPUT input)\n"
1201 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001202
1203 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1204 {
1205 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1206
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001207 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208 {
1209 vertexHLSL += "transpose";
1210 }
1211
1212 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1213 }
1214
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001215 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1216 {
1217 vertexHLSL += "\n"
1218 " dx_initConstantBuffers();\n";
1219 }
1220
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001221 if (shaderModel >= 4)
1222 {
1223 vertexHLSL += "\n"
1224 " gl_main();\n"
1225 "\n"
1226 " VS_OUTPUT output;\n"
1227 " output.gl_Position.x = gl_Position.x;\n"
1228 " output.gl_Position.y = -gl_Position.y;\n"
1229 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1230 " output.gl_Position.w = gl_Position.w;\n";
1231 }
1232 else
1233 {
1234 vertexHLSL += "\n"
1235 " gl_main();\n"
1236 "\n"
1237 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001238 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1239 " 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 +00001240 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1241 " output.gl_Position.w = gl_Position.w;\n";
1242 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001243
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001244 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001245 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001246 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001247 }
1248
1249 if (fragmentShader->mUsesFragCoord)
1250 {
1251 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1252 }
1253
1254 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1255 {
1256 if (varying->reg >= 0)
1257 {
1258 for (int i = 0; i < varying->size; i++)
1259 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001260 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001261
1262 for (int j = 0; j < rows; j++)
1263 {
1264 int r = varying->reg + i * rows + j;
1265 vertexHLSL += " output.v" + str(r);
1266
1267 bool sharedRegister = false; // Register used by multiple varyings
1268
1269 for (int x = 0; x < 4; x++)
1270 {
1271 if (packing[r][x] && packing[r][x] != packing[r][0])
1272 {
1273 sharedRegister = true;
1274 break;
1275 }
1276 }
1277
1278 if(sharedRegister)
1279 {
1280 vertexHLSL += ".";
1281
1282 for (int x = 0; x < 4; x++)
1283 {
1284 if (packing[r][x] == &*varying)
1285 {
1286 switch(x)
1287 {
1288 case 0: vertexHLSL += "x"; break;
1289 case 1: vertexHLSL += "y"; break;
1290 case 2: vertexHLSL += "z"; break;
1291 case 3: vertexHLSL += "w"; break;
1292 }
1293 }
1294 }
1295 }
1296
1297 vertexHLSL += " = " + varying->name;
1298
1299 if (varying->array)
1300 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001301 vertexHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001302 }
1303
1304 if (rows > 1)
1305 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001306 vertexHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001307 }
1308
1309 vertexHLSL += ";\n";
1310 }
1311 }
1312 }
1313 }
1314
1315 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001316 " return output;\n"
1317 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001318
1319 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001320 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001321
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001322 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001323
1324 if (fragmentShader->mUsesFragCoord)
1325 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001326 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001327 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001328
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001329 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1330 {
1331 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1332 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001333
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001334 // Must consume the PSIZE element if the geometry shader is not active
1335 // We won't know if we use a GS until we draw
1336 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1337 {
1338 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1339 }
1340
1341 if (fragmentShader->mUsesFragCoord)
1342 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001343 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001344 {
1345 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1346 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001347 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001348 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1350 }
1351 }
1352
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001353 pixelHLSL += "};\n"
1354 "\n"
1355 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001356 "{\n";
1357
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001358 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001359 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001360 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001361 }
1362
1363 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001364 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001365
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001366 if (fragmentShader->mUsesFrontFacing)
1367 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001368 if (shaderModel >= 4)
1369 {
1370 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1371 "{\n";
1372 }
1373 else
1374 {
1375 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1376 "{\n";
1377 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001378 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001379 else
1380 {
1381 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1382 "{\n";
1383 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001384
1385 if (fragmentShader->mUsesFragCoord)
1386 {
1387 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1388
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001389 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001390 {
1391 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1392 " gl_FragCoord.y = input.dx_VPos.y;\n";
1393 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001394 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001395 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001396 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001397 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001398 }
1399 else
1400 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001401 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1402 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1403 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001404 }
1405
daniel@transgaming.com12985182012-12-20 20:56:31 +00001406 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001407 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001408 }
1409
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001410 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001411 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001412 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1413 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001414 }
1415
1416 if (fragmentShader->mUsesFrontFacing)
1417 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001418 if (shaderModel <= 3)
1419 {
1420 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1421 }
1422 else
1423 {
1424 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1425 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001426 }
1427
1428 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1429 {
1430 if (varying->reg >= 0)
1431 {
1432 for (int i = 0; i < varying->size; i++)
1433 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001434 GLenum transposedType = TransposeMatrixType(varying->type);
1435 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001436 for (int j = 0; j < rows; j++)
1437 {
1438 std::string n = str(varying->reg + i * rows + j);
1439 pixelHLSL += " " + varying->name;
1440
1441 if (varying->array)
1442 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001443 pixelHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001444 }
1445
1446 if (rows > 1)
1447 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001448 pixelHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001449 }
1450
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001451 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001452 {
1453 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1454 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1455 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1456 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1457 default: UNREACHABLE();
1458 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001459 }
1460 }
1461 }
1462 else UNREACHABLE();
1463 }
1464
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001465 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1466 {
1467 pixelHLSL += "\n"
1468 " dx_initConstantBuffers();\n";
1469 }
1470
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001471 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001472 " gl_main();\n"
1473 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001474 " PS_OUTPUT output;\n";
1475
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001476 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001477 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001478 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001479
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001480 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001481 }
1482
1483 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001484 " return output;\n"
1485 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001486
1487 return true;
1488}
1489
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001490std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1491{
1492 std::string varyingHLSL;
1493
1494 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1495 {
1496 if (varying->reg >= 0)
1497 {
1498 for (int i = 0; i < varying->size; i++)
1499 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001500 GLenum transposedType = TransposeMatrixType(varying->type);
1501 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001502 for (int j = 0; j < rows; j++)
1503 {
1504 switch (varying->interpolation)
1505 {
1506 case Smooth: varyingHLSL += " "; break;
1507 case Flat: varyingHLSL += " nointerpolation "; break;
1508 case Centroid: varyingHLSL += " centroid "; break;
1509 default: UNREACHABLE();
1510 }
1511
1512 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001513 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001514
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001515 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001516 }
1517 }
1518 }
1519 else UNREACHABLE();
1520 }
1521
1522 return varyingHLSL;
1523}
1524
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001525bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1526{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001527 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001528
1529 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001530 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001531 if (format != GL_PROGRAM_BINARY_ANGLE)
1532 {
1533 infoLog.append("Invalid program binary format.");
1534 return false;
1535 }
1536
1537 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001538 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001539 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001540 {
1541 infoLog.append("Invalid program binary version.");
1542 return false;
1543 }
1544
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001545 int compileFlags = 0;
1546 stream.read(&compileFlags);
1547 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1548 {
1549 infoLog.append("Mismatched compilation flags.");
1550 return false;
1551 }
1552
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001553 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1554 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001555 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001556 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001557 stream.read(&name);
1558 mLinkedAttribute[i].name = name;
1559 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001560 }
1561
1562 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1563 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001564 stream.read(&mSamplersPS[i].active);
1565 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001566
1567 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001568 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001569 mSamplersPS[i].textureType = (TextureType) textureType;
1570 }
1571
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001572 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001573 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001574 stream.read(&mSamplersVS[i].active);
1575 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001576
1577 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001578 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001579 mSamplersVS[i].textureType = (TextureType) textureType;
1580 }
1581
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001582 stream.read(&mUsedVertexSamplerRange);
1583 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001584 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001585 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001586
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001587 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001588 stream.read(&size);
1589 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001590 {
1591 infoLog.append("Invalid program binary.");
1592 return false;
1593 }
1594
1595 mUniforms.resize(size);
1596 for (unsigned int i = 0; i < size; ++i)
1597 {
1598 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001599 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001600 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001602 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001603
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001604 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001605 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001606 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001607 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001608 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001609
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001610 int offset;
1611 int arrayStride;
1612 int matrixStride;
1613 bool isRowMajorMatrix;
1614
1615 stream.read(&offset);
1616 stream.read(&arrayStride);
1617 stream.read(&matrixStride);
1618 stream.read(&isRowMajorMatrix);
1619
1620 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1621
1622 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001624 stream.read(&mUniforms[i]->psRegisterIndex);
1625 stream.read(&mUniforms[i]->vsRegisterIndex);
1626 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 }
1628
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001629 stream.read(&size);
1630 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631 {
1632 infoLog.append("Invalid program binary.");
1633 return false;
1634 }
1635
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001636 mUniformBlocks.resize(size);
1637 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1638 {
1639 std::string name;
1640 unsigned int elementIndex;
1641 unsigned int dataSize;
1642
1643 stream.read(&name);
1644 stream.read(&elementIndex);
1645 stream.read(&dataSize);
1646
1647 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1648
1649 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1650 stream.read(&uniformBlock.psRegisterIndex);
1651 stream.read(&uniformBlock.vsRegisterIndex);
1652
1653 size_t numMembers;
1654 stream.read(&numMembers);
1655 uniformBlock.memberUniformIndexes.resize(numMembers);
1656 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1657 {
1658 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1659 }
1660 }
1661
1662 stream.read(&size);
1663 if (stream.error())
1664 {
1665 infoLog.append("Invalid program binary.");
1666 return false;
1667 }
1668
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669 mUniformIndex.resize(size);
1670 for (unsigned int i = 0; i < size; ++i)
1671 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 stream.read(&mUniformIndex[i].name);
1673 stream.read(&mUniformIndex[i].element);
1674 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 }
1676
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001677 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679
1680 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001683 unsigned int geometryShaderSize;
1684 stream.read(&geometryShaderSize);
1685
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001686 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001687
daniel@transgaming.com36038542012-11-28 20:59:26 +00001688 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001689 ptr += sizeof(GUID);
1690
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001691 GUID identifier = mRenderer->getAdapterIdentifier();
1692 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693 {
1694 infoLog.append("Invalid program binary.");
1695 return false;
1696 }
1697
1698 const char *pixelShaderFunction = ptr;
1699 ptr += pixelShaderSize;
1700
1701 const char *vertexShaderFunction = ptr;
1702 ptr += vertexShaderSize;
1703
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001704 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1705 ptr += geometryShaderSize;
1706
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001707 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001708 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001709 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710 {
1711 infoLog.append("Could not create pixel shader.");
1712 return false;
1713 }
1714
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001715 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001716 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001717 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001718 {
1719 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001720 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001721 mPixelExecutable = NULL;
1722 return false;
1723 }
1724
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001725 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1726 {
1727 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1728 geometryShaderSize, rx::SHADER_GEOMETRY);
1729 if (!mGeometryExecutable)
1730 {
1731 infoLog.append("Could not create geometry shader.");
1732 delete mPixelExecutable;
1733 mPixelExecutable = NULL;
1734 delete mVertexExecutable;
1735 mVertexExecutable = NULL;
1736 return false;
1737 }
1738 }
1739 else
1740 {
1741 mGeometryExecutable = NULL;
1742 }
1743
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001744 return true;
1745}
1746
1747bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1748{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001749 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001750
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001751 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001752 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001753 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754
1755 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1756 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001757 stream.write(mLinkedAttribute[i].type);
1758 stream.write(mLinkedAttribute[i].name);
1759 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760 }
1761
1762 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1763 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001764 stream.write(mSamplersPS[i].active);
1765 stream.write(mSamplersPS[i].logicalTextureUnit);
1766 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767 }
1768
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001769 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001770 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001771 stream.write(mSamplersVS[i].active);
1772 stream.write(mSamplersVS[i].logicalTextureUnit);
1773 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 }
1775
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.write(mUsedVertexSamplerRange);
1777 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001778 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001779 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001782 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001784 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001785
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001786 stream.write(uniform.type);
1787 stream.write(uniform.precision);
1788 stream.write(uniform.name);
1789 stream.write(uniform.arraySize);
1790 stream.write(uniform.blockIndex);
1791
1792 stream.write(uniform.blockInfo.offset);
1793 stream.write(uniform.blockInfo.arrayStride);
1794 stream.write(uniform.blockInfo.matrixStride);
1795 stream.write(uniform.blockInfo.isRowMajorMatrix);
1796
1797 stream.write(uniform.psRegisterIndex);
1798 stream.write(uniform.vsRegisterIndex);
1799 stream.write(uniform.registerCount);
1800 }
1801
1802 stream.write(mUniformBlocks.size());
1803 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1804 {
1805 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1806
1807 stream.write(uniformBlock.name);
1808 stream.write(uniformBlock.elementIndex);
1809 stream.write(uniformBlock.dataSize);
1810
1811 stream.write(uniformBlock.memberUniformIndexes.size());
1812 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1813 {
1814 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1815 }
1816
1817 stream.write(uniformBlock.psRegisterIndex);
1818 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819 }
1820
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001821 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1823 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001824 stream.write(mUniformIndex[i].name);
1825 stream.write(mUniformIndex[i].element);
1826 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001827 }
1828
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001829 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001830 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001832 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001833 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001835 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1836 stream.write(geometryShaderSize);
1837
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001838 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001839
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001840 GLsizei streamLength = stream.length();
1841 const void *streamData = stream.data();
1842
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001843 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001844 if (totalLength > bufSize)
1845 {
1846 if (length)
1847 {
1848 *length = 0;
1849 }
1850
1851 return false;
1852 }
1853
1854 if (binary)
1855 {
1856 char *ptr = (char*) binary;
1857
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001858 memcpy(ptr, streamData, streamLength);
1859 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001860
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001861 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001862 ptr += sizeof(GUID);
1863
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001864 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001865 ptr += pixelShaderSize;
1866
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001867 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001868 ptr += vertexShaderSize;
1869
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001870 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1871 {
1872 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1873 ptr += geometryShaderSize;
1874 }
1875
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001876 ASSERT(ptr - totalLength == binary);
1877 }
1878
1879 if (length)
1880 {
1881 *length = totalLength;
1882 }
1883
1884 return true;
1885}
1886
1887GLint ProgramBinary::getLength()
1888{
1889 GLint length;
1890 if (save(NULL, INT_MAX, &length))
1891 {
1892 return length;
1893 }
1894 else
1895 {
1896 return 0;
1897 }
1898}
1899
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001900bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001901{
1902 if (!fragmentShader || !fragmentShader->isCompiled())
1903 {
1904 return false;
1905 }
1906
1907 if (!vertexShader || !vertexShader->isCompiled())
1908 {
1909 return false;
1910 }
1911
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001912 mShaderVersion = vertexShader->getShaderVersion();
1913
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001914 std::string pixelHLSL = fragmentShader->getHLSL();
1915 std::string vertexHLSL = vertexShader->getHLSL();
1916
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001917 // Map the varyings to the register file
1918 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1919 int registers = packVaryings(infoLog, packing, fragmentShader);
1920
1921 if (registers < 0)
1922 {
1923 return false;
1924 }
1925
1926 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001927 {
1928 return false;
1929 }
1930
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001931 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001932 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1933 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001934
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001935 if (usesGeometryShader())
1936 {
1937 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1938 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1939 }
1940
1941 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001942 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001943 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001944 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001945
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001946 delete mVertexExecutable;
1947 mVertexExecutable = NULL;
1948 delete mPixelExecutable;
1949 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001950 delete mGeometryExecutable;
1951 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001952 }
1953
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001954 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1955 {
1956 success = false;
1957 }
1958
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001959 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001960 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001961 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001962 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001963
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001964 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1965 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1966 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001967 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1968 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1969 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 +00001970 }
1971
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001972 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1973 {
1974 success = false;
1975 }
1976
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001977 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001978}
1979
1980// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001981bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001982{
1983 unsigned int usedLocations = 0;
1984
1985 // Link attributes that have a binding location
1986 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1987 {
1988 int location = attributeBindings.getAttributeBinding(attribute->name);
1989
1990 if (location != -1) // Set by glBindAttribLocation
1991 {
1992 if (!mLinkedAttribute[location].name.empty())
1993 {
1994 // Multiple active attributes bound to the same location; not an error
1995 }
1996
1997 mLinkedAttribute[location] = *attribute;
1998
1999 int rows = VariableRowCount(attribute->type);
2000
2001 if (rows + location > MAX_VERTEX_ATTRIBS)
2002 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002003 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 +00002004
2005 return false;
2006 }
2007
2008 for (int i = 0; i < rows; i++)
2009 {
2010 usedLocations |= 1 << (location + i);
2011 }
2012 }
2013 }
2014
2015 // Link attributes that don't have a binding location
2016 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2017 {
2018 int location = attributeBindings.getAttributeBinding(attribute->name);
2019
2020 if (location == -1) // Not set by glBindAttribLocation
2021 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002022 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002023 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2024
2025 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2026 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002027 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002028
2029 return false; // Fail to link
2030 }
2031
2032 mLinkedAttribute[availableIndex] = *attribute;
2033 }
2034 }
2035
2036 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2037 {
2038 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002039 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002040
2041 for (int r = 0; r < rows; r++)
2042 {
2043 mSemanticIndex[attributeIndex++] = index++;
2044 }
2045 }
2046
2047 return true;
2048}
2049
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002050bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2051{
2052 if (vertexUniform.type != fragmentUniform.type)
2053 {
2054 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2055 return false;
2056 }
2057 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2058 {
2059 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2060 return false;
2061 }
2062 else if (vertexUniform.precision != fragmentUniform.precision)
2063 {
2064 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2065 return false;
2066 }
2067 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2068 {
2069 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2070 }
2071
2072 const unsigned int numMembers = vertexUniform.fields.size();
2073 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2074 {
2075 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2076 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2077
2078 if (vertexMember.name != fragmentMember.name)
2079 {
2080 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2081 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2082 return false;
2083 }
2084
2085 const std::string memberName = uniformName + "." + vertexUniform.name;
2086 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2087 {
2088 return false;
2089 }
2090 }
2091
2092 return true;
2093}
2094
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002095bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002096{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002097 // Check that uniforms defined in the vertex and fragment shaders are identical
2098 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2099 UniformMap linkedUniforms;
2100
2101 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2102 {
2103 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2104 linkedUniforms[vertexUniform.name] = &vertexUniform;
2105 }
2106
2107 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2108 {
2109 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2110 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2111 if (entry != linkedUniforms.end())
2112 {
2113 const sh::Uniform &vertexUniform = *entry->second;
2114 const std::string &uniformName = "uniform " + vertexUniform.name;
2115 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2116 {
2117 return false;
2118 }
2119 }
2120 }
2121
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002122 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002123 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002124 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002125 {
2126 return false;
2127 }
2128 }
2129
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002130 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002131 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002132 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002133 {
2134 return false;
2135 }
2136 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002137
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002138 return true;
2139}
2140
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002141int totalRegisterCount(const sh::Uniform &uniform)
2142{
2143 int registerCount = 0;
2144
2145 if (!uniform.fields.empty())
2146 {
2147 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2148 {
2149 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2150 }
2151 }
2152 else
2153 {
2154 registerCount = 1;
2155 }
2156
2157 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2158}
2159
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002160bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002161{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002162 if (!constant.fields.empty())
2163 {
2164 if (constant.arraySize > 0)
2165 {
2166 unsigned int elementRegisterIndex = constant.registerIndex;
2167
2168 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2169 {
2170 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2171 {
2172 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002173 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002174 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2175 if (!defineUniform(shader, fieldUniform, infoLog))
2176 {
2177 return false;
2178 }
2179 elementRegisterIndex += totalRegisterCount(field);
2180 }
2181 }
2182 }
2183 else
2184 {
2185 unsigned int fieldRegisterIndex = constant.registerIndex;
2186
2187 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2188 {
2189 const sh::Uniform &field = constant.fields[fieldIndex];
2190 const std::string &uniformName = constant.name + "." + field.name;
2191
2192 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2193 fieldUniform.fields = field.fields;
2194
2195 if (!defineUniform(shader, fieldUniform, infoLog))
2196 {
2197 return false;
2198 }
2199 fieldRegisterIndex += totalRegisterCount(field);
2200 }
2201 }
2202
2203 return true;
2204 }
2205
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002206 if (constant.type == GL_SAMPLER_2D ||
2207 constant.type == GL_SAMPLER_CUBE)
2208 {
2209 unsigned int samplerIndex = constant.registerIndex;
2210
2211 do
2212 {
2213 if (shader == GL_VERTEX_SHADER)
2214 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002215 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002216 {
2217 mSamplersVS[samplerIndex].active = true;
2218 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2219 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2220 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2221 }
2222 else
2223 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002224 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002225 return false;
2226 }
2227 }
2228 else if (shader == GL_FRAGMENT_SHADER)
2229 {
2230 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2231 {
2232 mSamplersPS[samplerIndex].active = true;
2233 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2234 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2235 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2236 }
2237 else
2238 {
2239 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2240 return false;
2241 }
2242 }
2243 else UNREACHABLE();
2244
2245 samplerIndex++;
2246 }
2247 while (samplerIndex < constant.registerIndex + constant.arraySize);
2248 }
2249
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002250 Uniform *uniform = NULL;
2251 GLint location = getUniformLocation(constant.name);
2252
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002253 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002254 {
2255 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002256 }
2257 else
2258 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002259 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002260 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002261
2262 if (!uniform)
2263 {
2264 return false;
2265 }
2266
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002267 if (shader == GL_FRAGMENT_SHADER)
2268 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002269 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002270 }
2271 else if (shader == GL_VERTEX_SHADER)
2272 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002273 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002274 }
2275 else UNREACHABLE();
2276
2277 if (location >= 0)
2278 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002279 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002280 }
2281
2282 mUniforms.push_back(uniform);
2283 unsigned int uniformIndex = mUniforms.size() - 1;
2284
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002285 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002286 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002287 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002288 }
2289
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002290 if (shader == GL_VERTEX_SHADER)
2291 {
2292 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2293 {
2294 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2295 return false;
2296 }
2297 }
2298 else if (shader == GL_FRAGMENT_SHADER)
2299 {
2300 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2301 {
2302 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2303 return false;
2304 }
2305 }
2306 else UNREACHABLE();
2307
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002308 return true;
2309}
2310
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002311bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2312{
2313 const char* blockName = vertexInterfaceBlock.name.c_str();
2314
2315 // validate blocks for the same member types
2316 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2317 {
2318 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2319 return false;
2320 }
2321
2322 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2323 {
2324 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2325 return false;
2326 }
2327
2328 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2329 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2330 {
2331 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2332 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2333
2334 if (vertexMember.name != fragmentMember.name)
2335 {
2336 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2337 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2338 return false;
2339 }
2340
2341 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2342 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2343 {
2344 return false;
2345 }
2346 }
2347
2348 return true;
2349}
2350
2351bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2352{
2353 // Check that interface blocks defined in the vertex and fragment shaders are identical
2354 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2355 UniformBlockMap linkedUniformBlocks;
2356
2357 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2358 {
2359 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2360 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2361 }
2362
2363 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2364 {
2365 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2366 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2367 if (entry != linkedUniformBlocks.end())
2368 {
2369 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2370 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2371 {
2372 return false;
2373 }
2374 }
2375 }
2376
2377 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2378 {
2379 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2380 {
2381 return false;
2382 }
2383 }
2384
2385 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2386 {
2387 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2388 {
2389 return false;
2390 }
2391 }
2392
2393 return true;
2394}
2395
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002396void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2397{
2398 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2399 {
2400 const sh::Uniform &uniform = uniforms[uniformIndex];
2401
2402 if (!uniform.fields.empty())
2403 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002404 if (uniform.arraySize > 0)
2405 {
2406 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2407 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002408 const std::string uniformElementName = uniform.name + arrayString(arrayElement);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002409 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2410 }
2411 }
2412 else
2413 {
2414 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2415 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002416 }
2417 else
2418 {
2419 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2420 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2421 blockIndex, **blockInfoItr);
2422
2423 // add to uniform list, but not index, since uniform block uniforms have no location
2424 blockUniformIndexes->push_back(mUniforms.size());
2425 mUniforms.push_back(newUniform);
2426 (*blockInfoItr)++;
2427 }
2428 }
2429}
2430
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002431bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2432{
2433 // create uniform block entries if they do not exist
2434 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2435 {
2436 std::vector<unsigned int> blockUniformIndexes;
2437 const unsigned int blockIndex = mUniformBlocks.size();
2438
2439 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002440 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2441 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002442
2443 // create all the uniform blocks
2444 if (interfaceBlock.arraySize > 0)
2445 {
2446 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2447 {
2448 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2449 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2450 mUniformBlocks.push_back(newUniformBlock);
2451 }
2452 }
2453 else
2454 {
2455 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2456 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2457 mUniformBlocks.push_back(newUniformBlock);
2458 }
2459 }
2460
2461 // Assign registers to the uniform blocks
2462 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2463 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2464 ASSERT(blockIndex != GL_INVALID_INDEX);
2465 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2466
2467 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2468 {
2469 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2470 ASSERT(uniformBlock->name == interfaceBlock.name);
2471
2472 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2473 {
2474 return false;
2475 }
2476 }
2477
2478 return true;
2479}
2480
2481bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2482{
2483 if (shader == GL_VERTEX_SHADER)
2484 {
2485 uniformBlock->vsRegisterIndex = registerIndex;
2486 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2487
2488 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2489 {
2490 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2491 return false;
2492 }
2493 }
2494 else if (shader == GL_FRAGMENT_SHADER)
2495 {
2496 uniformBlock->psRegisterIndex = registerIndex;
2497 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2498
2499 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2500 {
2501 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2502 return false;
2503 }
2504 }
2505 else UNREACHABLE();
2506
2507 return true;
2508}
2509
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002510std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2511{
2512 // for now we only handle point sprite emulation
2513 ASSERT(usesPointSpriteEmulation());
2514 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2515}
2516
2517std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2518{
2519 ASSERT(registers >= 0);
2520 ASSERT(vertexShader->mUsesPointSize);
2521 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2522
2523 std::string geomHLSL;
2524
2525 std::string varyingSemantic = "TEXCOORD";
2526
2527 std::string fragCoordSemantic;
2528 std::string pointCoordSemantic;
2529
2530 int reservedRegisterIndex = registers;
2531
2532 if (fragmentShader->mUsesFragCoord)
2533 {
2534 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2535 }
2536
2537 if (fragmentShader->mUsesPointCoord)
2538 {
2539 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2540 }
2541
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002542 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2543 "\n"
2544 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002545 "{\n";
2546
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002547 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002548
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002549 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002550
2551 if (fragmentShader->mUsesFragCoord)
2552 {
2553 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2554 }
2555
2556 geomHLSL += " float gl_PointSize : PSIZE;\n"
2557 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002558 "};\n"
2559 "\n"
2560 "struct GS_OUTPUT\n"
2561 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002562
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002563 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002564
2565 if (fragmentShader->mUsesFragCoord)
2566 {
2567 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2568 }
2569
2570 if (fragmentShader->mUsesPointCoord)
2571 {
2572 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2573 }
2574
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002575 geomHLSL += " float gl_PointSize : PSIZE;\n"
2576 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002577 "};\n"
2578 "\n"
2579 "static float2 pointSpriteCorners[] = \n"
2580 "{\n"
2581 " float2( 0.5f, -0.5f),\n"
2582 " float2( 0.5f, 0.5f),\n"
2583 " float2(-0.5f, -0.5f),\n"
2584 " float2(-0.5f, 0.5f)\n"
2585 "};\n"
2586 "\n"
2587 "static float2 pointSpriteTexcoords[] = \n"
2588 "{\n"
2589 " float2(1.0f, 1.0f),\n"
2590 " float2(1.0f, 0.0f),\n"
2591 " float2(0.0f, 1.0f),\n"
2592 " float2(0.0f, 0.0f)\n"
2593 "};\n"
2594 "\n"
2595 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2596 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2597 "\n"
2598 "[maxvertexcount(4)]\n"
2599 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2600 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002601 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2602 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002603
2604 for (int r = 0; r < registers; r++)
2605 {
2606 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2607 }
2608
2609 if (fragmentShader->mUsesFragCoord)
2610 {
2611 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2612 }
2613
2614 geomHLSL += " \n"
2615 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2616 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002617 " 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 +00002618
2619 for (int corner = 0; corner < 4; corner++)
2620 {
2621 geomHLSL += " \n"
2622 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2623
2624 if (fragmentShader->mUsesPointCoord)
2625 {
2626 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2627 }
2628
2629 geomHLSL += " outStream.Append(output);\n";
2630 }
2631
2632 geomHLSL += " \n"
2633 " outStream.RestartStrip();\n"
2634 "}\n";
2635
2636 return geomHLSL;
2637}
2638
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002639// This method needs to match OutputHLSL::decorate
2640std::string ProgramBinary::decorateAttribute(const std::string &name)
2641{
2642 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2643 {
2644 return "_" + name;
2645 }
2646
2647 return name;
2648}
2649
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002650bool ProgramBinary::isValidated() const
2651{
2652 return mValidated;
2653}
2654
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002655void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002656{
2657 // Skip over inactive attributes
2658 unsigned int activeAttribute = 0;
2659 unsigned int attribute;
2660 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2661 {
2662 if (mLinkedAttribute[attribute].name.empty())
2663 {
2664 continue;
2665 }
2666
2667 if (activeAttribute == index)
2668 {
2669 break;
2670 }
2671
2672 activeAttribute++;
2673 }
2674
2675 if (bufsize > 0)
2676 {
2677 const char *string = mLinkedAttribute[attribute].name.c_str();
2678
2679 strncpy(name, string, bufsize);
2680 name[bufsize - 1] = '\0';
2681
2682 if (length)
2683 {
2684 *length = strlen(name);
2685 }
2686 }
2687
2688 *size = 1; // Always a single 'type' instance
2689
2690 *type = mLinkedAttribute[attribute].type;
2691}
2692
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002693GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002694{
2695 int count = 0;
2696
2697 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2698 {
2699 if (!mLinkedAttribute[attributeIndex].name.empty())
2700 {
2701 count++;
2702 }
2703 }
2704
2705 return count;
2706}
2707
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002708GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002709{
2710 int maxLength = 0;
2711
2712 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2713 {
2714 if (!mLinkedAttribute[attributeIndex].name.empty())
2715 {
2716 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2717 }
2718 }
2719
2720 return maxLength;
2721}
2722
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002723void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002724{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002725 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002726
2727 if (bufsize > 0)
2728 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002729 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002730
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002731 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002732 {
2733 string += "[0]";
2734 }
2735
2736 strncpy(name, string.c_str(), bufsize);
2737 name[bufsize - 1] = '\0';
2738
2739 if (length)
2740 {
2741 *length = strlen(name);
2742 }
2743 }
2744
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002745 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002746
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002747 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002748}
2749
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002750GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002751{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002752 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002753}
2754
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002755GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002756{
2757 int maxLength = 0;
2758
2759 unsigned int numUniforms = mUniforms.size();
2760 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2761 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002762 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002763 {
2764 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2765 if (mUniforms[uniformIndex]->isArray())
2766 {
2767 length += 3; // Counting in "[0]".
2768 }
2769 maxLength = std::max(length, maxLength);
2770 }
2771 }
2772
2773 return maxLength;
2774}
2775
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002776GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2777{
2778 const gl::Uniform& uniform = *mUniforms[index];
2779
2780 switch (pname)
2781 {
2782 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2783 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002784 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 +00002785 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002786
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002787 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2788 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2789 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2790 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002791
2792 default:
2793 UNREACHABLE();
2794 break;
2795 }
2796 return 0;
2797}
2798
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002799void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2800{
2801 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2802
2803 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2804
2805 if (bufSize > 0)
2806 {
2807 std::string string = uniformBlock.name;
2808
2809 if (uniformBlock.isArrayElement())
2810 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002811 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002812 }
2813
2814 strncpy(uniformBlockName, string.c_str(), bufSize);
2815 uniformBlockName[bufSize - 1] = '\0';
2816
2817 if (length)
2818 {
2819 *length = strlen(uniformBlockName);
2820 }
2821 }
2822}
2823
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002824void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2825{
2826 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2827
2828 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2829
2830 switch (pname)
2831 {
2832 case GL_UNIFORM_BLOCK_DATA_SIZE:
2833 *params = static_cast<GLint>(uniformBlock.dataSize);
2834 break;
2835 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002836 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002837 break;
2838 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2839 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2840 break;
2841 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2842 {
2843 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2844 {
2845 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2846 }
2847 }
2848 break;
2849 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2850 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2851 break;
2852 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2853 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2854 break;
2855 default: UNREACHABLE();
2856 }
2857}
2858
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002859GLuint ProgramBinary::getActiveUniformBlockCount() const
2860{
2861 return mUniformBlocks.size();
2862}
2863
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002864GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2865{
2866 unsigned int maxLength = 0;
2867
2868 unsigned int numUniformBlocks = mUniformBlocks.size();
2869 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2870 {
2871 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2872 if (!uniformBlock.name.empty())
2873 {
2874 const unsigned int length = uniformBlock.name.length() + 1;
2875
2876 // Counting in "[0]".
2877 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2878
2879 maxLength = std::max(length + arrayLength, maxLength);
2880 }
2881 }
2882
2883 return maxLength;
2884}
2885
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002886void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002887{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002888 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002889 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002890 {
2891 mValidated = false;
2892 }
2893 else
2894 {
2895 mValidated = true;
2896 }
2897}
2898
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002899bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002900{
2901 // if any two active samplers in a program are of different types, but refer to the same
2902 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2903 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2904
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002905 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002906 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002907
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002908 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002909 {
2910 textureUnitType[i] = TEXTURE_UNKNOWN;
2911 }
2912
2913 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2914 {
2915 if (mSamplersPS[i].active)
2916 {
2917 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2918
2919 if (unit >= maxCombinedTextureImageUnits)
2920 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002921 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002922 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002923 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002924 }
2925
2926 return false;
2927 }
2928
2929 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2930 {
2931 if (mSamplersPS[i].textureType != textureUnitType[unit])
2932 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002933 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002934 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002935 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002936 }
2937
2938 return false;
2939 }
2940 }
2941 else
2942 {
2943 textureUnitType[unit] = mSamplersPS[i].textureType;
2944 }
2945 }
2946 }
2947
2948 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2949 {
2950 if (mSamplersVS[i].active)
2951 {
2952 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2953
2954 if (unit >= maxCombinedTextureImageUnits)
2955 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002956 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002957 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002958 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002959 }
2960
2961 return false;
2962 }
2963
2964 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2965 {
2966 if (mSamplersVS[i].textureType != textureUnitType[unit])
2967 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002968 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002969 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002970 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002971 }
2972
2973 return false;
2974 }
2975 }
2976 else
2977 {
2978 textureUnitType[unit] = mSamplersVS[i].textureType;
2979 }
2980 }
2981 }
2982
2983 return true;
2984}
2985
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002986ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2987{
2988}
2989
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002990struct AttributeSorter
2991{
2992 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2993 : originalIndices(semanticIndices)
2994 {
2995 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2996 {
2997 indices[i] = i;
2998 }
2999
3000 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3001 }
3002
3003 bool operator()(int a, int b)
3004 {
3005 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3006 }
3007
3008 int indices[MAX_VERTEX_ATTRIBS];
3009 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3010};
3011
3012void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3013{
3014 AttributeSorter sorter(mSemanticIndex);
3015
3016 int oldIndices[MAX_VERTEX_ATTRIBS];
3017 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3018
3019 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3020 {
3021 oldIndices[i] = mSemanticIndex[i];
3022 oldTranslatedAttributes[i] = attributes[i];
3023 }
3024
3025 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3026 {
3027 int oldIndex = sorter.indices[i];
3028 sortedSemanticIndices[i] = oldIndices[oldIndex];
3029 attributes[i] = oldTranslatedAttributes[oldIndex];
3030 }
3031}
3032
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003033}