blob: 9c3c3a980a854c2ba64e0a949eec215a3b36eebb [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000039namespace gl_d3d
40{
41 std::string TypeString(GLenum type)
42 {
43 switch (type)
44 {
45 case GL_FLOAT: return "float";
46 case GL_FLOAT_VEC2: return "float2";
47 case GL_FLOAT_VEC3: return "float3";
48 case GL_FLOAT_VEC4: return "float4";
49 case GL_FLOAT_MAT2: return "float2x2";
50 case GL_FLOAT_MAT3: return "float3x3";
51 case GL_FLOAT_MAT4: return "float4x4";
52 case GL_FLOAT_MAT2x3: return "float2x3";
53 case GL_FLOAT_MAT3x2: return "float3x2";
54 case GL_FLOAT_MAT2x4: return "float2x4";
55 case GL_FLOAT_MAT4x2: return "float4x2";
56 case GL_FLOAT_MAT3x4: return "float3x4";
57 case GL_FLOAT_MAT4x3: return "float4x3";
58 default: UNREACHABLE(); return "invalid-gl-type";
59 }
60 }
61}
62
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000063namespace
64{
65
66unsigned int parseAndStripArrayIndex(std::string* name)
67{
68 unsigned int subscript = GL_INVALID_INDEX;
69
70 // Strip any trailing array operator and retrieve the subscript
71 size_t open = name->find_last_of('[');
72 size_t close = name->find_last_of(']');
73 if (open != std::string::npos && close == name->length() - 1)
74 {
75 subscript = atoi(name->substr(open + 1).c_str());
76 name->erase(open);
77 }
78
79 return subscript;
80}
81
82}
83
daniel@transgaming.comdb019952012-12-20 21:13:32 +000084UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
85 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000086{
87}
88
daniel@transgaming.come87ca002012-07-24 18:30:43 +000089unsigned int ProgramBinary::mCurrentSerial = 1;
90
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000091ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000092{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000093 mPixelExecutable = NULL;
94 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000095 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000096
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097 mValidated = false;
98
99 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
100 {
101 mSemanticIndex[index] = -1;
102 }
103
104 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
105 {
106 mSamplersPS[index].active = false;
107 }
108
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000109 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000110 {
111 mSamplersVS[index].active = false;
112 }
113
114 mUsedVertexSamplerRange = 0;
115 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000116 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000117 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118}
119
120ProgramBinary::~ProgramBinary()
121{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000122 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000123 mPixelExecutable = NULL;
124
daniel@transgaming.com95892412012-11-28 20:59:09 +0000125 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000126 mVertexExecutable = NULL;
127
128 delete mGeometryExecutable;
129 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000130
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000131 while (!mUniforms.empty())
132 {
133 delete mUniforms.back();
134 mUniforms.pop_back();
135 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000136
137 while (!mUniformBlocks.empty())
138 {
139 delete mUniformBlocks.back();
140 mUniformBlocks.pop_back();
141 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000142}
143
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000144unsigned int ProgramBinary::getSerial() const
145{
146 return mSerial;
147}
148
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000149int ProgramBinary::getShaderVersion() const
150{
151 return mShaderVersion;
152}
153
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000154unsigned int ProgramBinary::issueSerial()
155{
156 return mCurrentSerial++;
157}
158
daniel@transgaming.com95892412012-11-28 20:59:09 +0000159rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000160{
161 return mPixelExecutable;
162}
163
daniel@transgaming.com95892412012-11-28 20:59:09 +0000164rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000165{
166 return mVertexExecutable;
167}
168
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000169rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
170{
171 return mGeometryExecutable;
172}
173
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000174GLuint ProgramBinary::getAttributeLocation(const char *name)
175{
176 if (name)
177 {
178 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
179 {
180 if (mLinkedAttribute[index].name == std::string(name))
181 {
182 return index;
183 }
184 }
185 }
186
187 return -1;
188}
189
190int ProgramBinary::getSemanticIndex(int attributeIndex)
191{
192 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
193
194 return mSemanticIndex[attributeIndex];
195}
196
197// Returns one more than the highest sampler index used.
198GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
199{
200 switch (type)
201 {
202 case SAMPLER_PIXEL:
203 return mUsedPixelSamplerRange;
204 case SAMPLER_VERTEX:
205 return mUsedVertexSamplerRange;
206 default:
207 UNREACHABLE();
208 return 0;
209 }
210}
211
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000212bool ProgramBinary::usesPointSize() const
213{
214 return mUsesPointSize;
215}
216
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000217bool ProgramBinary::usesPointSpriteEmulation() const
218{
219 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
220}
221
222bool ProgramBinary::usesGeometryShader() const
223{
224 return usesPointSpriteEmulation();
225}
226
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000227// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
228// index (0-15 for the pixel shader and 0-3 for the vertex shader).
229GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
230{
231 GLint logicalTextureUnit = -1;
232
233 switch (type)
234 {
235 case SAMPLER_PIXEL:
236 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
237
238 if (mSamplersPS[samplerIndex].active)
239 {
240 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
241 }
242 break;
243 case SAMPLER_VERTEX:
244 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
245
246 if (mSamplersVS[samplerIndex].active)
247 {
248 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
249 }
250 break;
251 default: UNREACHABLE();
252 }
253
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000254 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000255 {
256 return logicalTextureUnit;
257 }
258
259 return -1;
260}
261
262// Returns the texture type for a given Direct3D 9 sampler type and
263// index (0-15 for the pixel shader and 0-3 for the vertex shader).
264TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
265{
266 switch (type)
267 {
268 case SAMPLER_PIXEL:
269 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
270 ASSERT(mSamplersPS[samplerIndex].active);
271 return mSamplersPS[samplerIndex].textureType;
272 case SAMPLER_VERTEX:
273 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
274 ASSERT(mSamplersVS[samplerIndex].active);
275 return mSamplersVS[samplerIndex].textureType;
276 default: UNREACHABLE();
277 }
278
279 return TEXTURE_2D;
280}
281
282GLint ProgramBinary::getUniformLocation(std::string name)
283{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000284 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000285
286 unsigned int numUniforms = mUniformIndex.size();
287 for (unsigned int location = 0; location < numUniforms; location++)
288 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000289 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000290 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000291 const int index = mUniformIndex[location].index;
292 const bool isArray = mUniforms[index]->isArray();
293
294 if ((isArray && mUniformIndex[location].element == subscript) ||
295 (subscript == GL_INVALID_INDEX))
296 {
297 return location;
298 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000299 }
300 }
301
302 return -1;
303}
304
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000305GLuint ProgramBinary::getUniformIndex(std::string name)
306{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000307 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000308
309 // The app is not allowed to specify array indices other than 0 for arrays of basic types
310 if (subscript != 0 && subscript != GL_INVALID_INDEX)
311 {
312 return GL_INVALID_INDEX;
313 }
314
315 unsigned int numUniforms = mUniforms.size();
316 for (unsigned int index = 0; index < numUniforms; index++)
317 {
318 if (mUniforms[index]->name == name)
319 {
320 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
321 {
322 return index;
323 }
324 }
325 }
326
327 return GL_INVALID_INDEX;
328}
329
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000330GLuint ProgramBinary::getUniformBlockIndex(std::string name)
331{
332 unsigned int subscript = parseAndStripArrayIndex(&name);
333
334 unsigned int numUniformBlocks = mUniformBlocks.size();
335 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
336 {
337 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
338 if (uniformBlock.name == name)
339 {
340 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
341 if (subscript == uniformBlock.elementIndex || arrayElementZero)
342 {
343 return blockIndex;
344 }
345 }
346 }
347
348 return GL_INVALID_INDEX;
349}
350
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000351UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
352{
353 ASSERT(blockIndex < mUniformBlocks.size());
354 return mUniformBlocks[blockIndex];
355}
356
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000357template <typename T>
358bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000359{
360 if (location < 0 || location >= (int)mUniformIndex.size())
361 {
362 return false;
363 }
364
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000365 const int components = UniformComponentCount(targetUniformType);
366 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
367
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000368 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
369 targetUniform->dirty = true;
370
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000371 int elementCount = targetUniform->elementCount();
372
373 if (elementCount == 1 && count > 1)
374 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
375
376 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
377
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000378 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000379 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000380 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000381
382 for (int i = 0; i < count; i++)
383 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000384 for (int c = 0; c < components; c++)
385 {
386 target[c] = v[c];
387 }
388 for (int c = components; c < 4; c++)
389 {
390 target[c] = 0;
391 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000393 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394 }
395 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000396 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000397 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000398 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000400 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000401 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000402 for (int c = 0; c < components; c++)
403 {
404 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
405 }
406 for (int c = components; c < 4; c++)
407 {
408 boolParams[c] = GL_FALSE;
409 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000410 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000411 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412 }
413 }
414 else
415 {
416 return false;
417 }
418
419 return true;
420}
421
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000422bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
423{
424 return setUniform(location, count, v, GL_FLOAT);
425}
426
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000427bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
428{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000429 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000430}
431
432bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
433{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000434 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435}
436
437bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
438{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000439 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000440}
441
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000442template<typename T>
443void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000444{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000445 int copyWidth = std::min(targetHeight, srcWidth);
446 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000447
448 for (int x = 0; x < copyWidth; x++)
449 {
450 for (int y = 0; y < copyHeight; y++)
451 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000452 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000453 }
454 }
455 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000456 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000457 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000458 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000459 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000460 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000461 }
462 }
463 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000464 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465 {
466 for (int x = 0; x < targetWidth; x++)
467 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000468 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000469 }
470 }
471}
472
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000473template<typename T>
474void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
475{
476 int copyWidth = std::min(targetWidth, srcWidth);
477 int copyHeight = std::min(targetHeight, srcHeight);
478
479 for (int y = 0; y < copyHeight; y++)
480 {
481 for (int x = 0; x < copyWidth; x++)
482 {
483 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
484 }
485 }
486 // clear unfilled right side
487 for (int y = 0; y < copyHeight; y++)
488 {
489 for (int x = copyWidth; x < targetWidth; x++)
490 {
491 target[y * targetWidth + x] = static_cast<T>(0);
492 }
493 }
494 // clear unfilled bottom.
495 for (int y = copyHeight; y < targetHeight; y++)
496 {
497 for (int x = 0; x < targetWidth; x++)
498 {
499 target[y * targetWidth + x] = static_cast<T>(0);
500 }
501 }
502}
503
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000504template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000505bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000506{
507 if (location < 0 || location >= (int)mUniformIndex.size())
508 {
509 return false;
510 }
511
512 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
513 targetUniform->dirty = true;
514
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000515 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000516 {
517 return false;
518 }
519
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000520 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000521
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000522 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000523 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
524
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000525 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000526 const unsigned int targetMatrixStride = (4 * rows);
527 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000528
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529 for (int i = 0; i < count; i++)
530 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000531 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
532 if (transpose == GL_FALSE)
533 {
534 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
535 }
536 else
537 {
538 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
539 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000540 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000541 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542 }
543
544 return true;
545}
546
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000547bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000548{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000549 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000550}
551
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000552bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000553{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000554 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555}
556
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000557bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000558{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000559 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560}
561
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000562bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000563{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000564 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000565}
566
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000568{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000569 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000570}
571
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000572bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000573{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000574 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000575}
576
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000577bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000578{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000579 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000580}
581
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000582bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000583{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000584 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000585}
586
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000587bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000588{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000589 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000590}
591
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000592bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
593{
594 if (location < 0 || location >= (int)mUniformIndex.size())
595 {
596 return false;
597 }
598
599 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
600 targetUniform->dirty = true;
601
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000602 int elementCount = targetUniform->elementCount();
603
604 if (elementCount == 1 && count > 1)
605 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
606
607 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
608
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000609 if (targetUniform->type == GL_INT ||
610 targetUniform->type == GL_SAMPLER_2D ||
611 targetUniform->type == GL_SAMPLER_CUBE)
612 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000613 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000615 for (int i = 0; i < count; i++)
616 {
617 target[0] = v[0];
618 target[1] = 0;
619 target[2] = 0;
620 target[3] = 0;
621 target += 4;
622 v += 1;
623 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624 }
625 else if (targetUniform->type == GL_BOOL)
626 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000627 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000629 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000630 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000631 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
632 boolParams[1] = GL_FALSE;
633 boolParams[2] = GL_FALSE;
634 boolParams[3] = GL_FALSE;
635 boolParams += 4;
636 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000637 }
638 }
639 else
640 {
641 return false;
642 }
643
644 return true;
645}
646
647bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
648{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000649 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000650}
651
652bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
653{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000654 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000655}
656
657bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
658{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000659 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000660}
661
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000662bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
663{
664 return setUniform(location, count, v, GL_UNSIGNED_INT);
665}
666
667bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
668{
669 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
670}
671
672bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
673{
674 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
675}
676
677bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
678{
679 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
680}
681
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000682template <typename T>
683bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000684{
685 if (location < 0 || location >= (int)mUniformIndex.size())
686 {
687 return false;
688 }
689
690 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
691
692 // sized queries -- ensure the provided buffer is large enough
693 if (bufSize)
694 {
695 int requiredBytes = UniformExternalSize(targetUniform->type);
696 if (*bufSize < requiredBytes)
697 {
698 return false;
699 }
700 }
701
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000702 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000703 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000704 const int rows = VariableRowCount(targetUniform->type);
705 const int cols = VariableColumnCount(targetUniform->type);
706 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
707 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000708 else if (uniformType == UniformComponentType(targetUniform->type))
709 {
710 unsigned int size = UniformComponentCount(targetUniform->type);
711 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
712 size * sizeof(T));
713 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000714 else
715 {
716 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000717 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000718 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000719 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000721 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000722
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000723 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000724 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000725 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000727 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000728 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000729
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000730 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000731 {
732 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
733
734 for (unsigned int i = 0; i < size; i++)
735 {
736 params[i] = static_cast<T>(floatParams[i]);
737 }
738 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000740
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000741 case GL_INT:
742 {
743 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
744
745 for (unsigned int i = 0; i < size; i++)
746 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000747 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000748 }
749 }
750 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000751
752 case GL_UNSIGNED_INT:
753 {
754 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000755
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000756 for (unsigned int i = 0; i < size; i++)
757 {
758 params[i] = static_cast<T>(uintParams[i]);
759 }
760 }
761 break;
762
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000763 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000764 }
765 }
766
767 return true;
768}
769
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000770bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
771{
772 return getUniformv(location, bufSize, params, GL_FLOAT);
773}
774
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000775bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
776{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000777 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000778}
779
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000780bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
781{
782 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
783}
784
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000785void ProgramBinary::dirtyAllUniforms()
786{
787 unsigned int numUniforms = mUniforms.size();
788 for (unsigned int index = 0; index < numUniforms; index++)
789 {
790 mUniforms[index]->dirty = true;
791 }
792}
793
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000794// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000795void ProgramBinary::applyUniforms()
796{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000797 // Retrieve sampler uniform values
798 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
799 {
800 Uniform *targetUniform = *ub;
801
802 if (targetUniform->dirty)
803 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000804 if (targetUniform->type == GL_SAMPLER_2D ||
805 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000806 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000807 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000808 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000809
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000810 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000811 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000812 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000813
814 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000815 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000816 unsigned int samplerIndex = firstIndex + i;
817
818 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000819 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000820 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000821 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000822 }
823 }
824 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000825
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000826 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000827 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000828 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000829
830 for (int i = 0; i < count; i++)
831 {
832 unsigned int samplerIndex = firstIndex + i;
833
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000834 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000835 {
836 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000837 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000838 }
839 }
840 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000841 }
842 }
843 }
844
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000845 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000846}
847
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000848bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
849{
850 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
851 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
852
853 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
854 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
855
856 ASSERT(boundBuffers.size() == mUniformBlocks.size());
857
858 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
859 {
860 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
861 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
862
863 ASSERT(uniformBlock && uniformBuffer);
864
865 if (uniformBuffer->size() < uniformBlock->dataSize)
866 {
867 // undefined behaviour
868 return false;
869 }
870
871 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
872
873 if (uniformBlock->isReferencedByVertexShader())
874 {
875 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
876 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
877 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
878 vertexUniformBuffers[registerIndex] = uniformBuffer;
879 }
880
881 if (uniformBlock->isReferencedByFragmentShader())
882 {
883 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
884 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
885 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
886 fragmentUniformBuffers[registerIndex] = uniformBuffer;
887 }
888 }
889
890 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
891}
892
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000893// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
894// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000895int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000896{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000897 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000898
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000899 fragmentShader->resetVaryingsRegisterAssignment();
900
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000901 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
902 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000903 GLenum transposedType = TransposeMatrixType(varying->type);
904 int n = VariableRowCount(transposedType) * varying->size;
905 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000906 bool success = false;
907
908 if (m == 2 || m == 3 || m == 4)
909 {
910 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
911 {
912 bool available = true;
913
914 for (int y = 0; y < n && available; y++)
915 {
916 for (int x = 0; x < m && available; x++)
917 {
918 if (packing[r + y][x])
919 {
920 available = false;
921 }
922 }
923 }
924
925 if (available)
926 {
927 varying->reg = r;
928 varying->col = 0;
929
930 for (int y = 0; y < n; y++)
931 {
932 for (int x = 0; x < m; x++)
933 {
934 packing[r + y][x] = &*varying;
935 }
936 }
937
938 success = true;
939 }
940 }
941
942 if (!success && m == 2)
943 {
944 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
945 {
946 bool available = true;
947
948 for (int y = 0; y < n && available; y++)
949 {
950 for (int x = 2; x < 4 && available; x++)
951 {
952 if (packing[r + y][x])
953 {
954 available = false;
955 }
956 }
957 }
958
959 if (available)
960 {
961 varying->reg = r;
962 varying->col = 2;
963
964 for (int y = 0; y < n; y++)
965 {
966 for (int x = 2; x < 4; x++)
967 {
968 packing[r + y][x] = &*varying;
969 }
970 }
971
972 success = true;
973 }
974 }
975 }
976 }
977 else if (m == 1)
978 {
979 int space[4] = {0};
980
981 for (int y = 0; y < maxVaryingVectors; y++)
982 {
983 for (int x = 0; x < 4; x++)
984 {
985 space[x] += packing[y][x] ? 0 : 1;
986 }
987 }
988
989 int column = 0;
990
991 for (int x = 0; x < 4; x++)
992 {
993 if (space[x] >= n && space[x] < space[column])
994 {
995 column = x;
996 }
997 }
998
999 if (space[column] >= n)
1000 {
1001 for (int r = 0; r < maxVaryingVectors; r++)
1002 {
1003 if (!packing[r][column])
1004 {
1005 varying->reg = r;
1006
1007 for (int y = r; y < r + n; y++)
1008 {
1009 packing[y][column] = &*varying;
1010 }
1011
1012 break;
1013 }
1014 }
1015
1016 varying->col = column;
1017
1018 success = true;
1019 }
1020 }
1021 else UNREACHABLE();
1022
1023 if (!success)
1024 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001025 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001026
1027 return -1;
1028 }
1029 }
1030
1031 // Return the number of used registers
1032 int registers = 0;
1033
1034 for (int r = 0; r < maxVaryingVectors; r++)
1035 {
1036 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1037 {
1038 registers++;
1039 }
1040 }
1041
1042 return registers;
1043}
1044
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001045bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1046 std::string& pixelHLSL, std::string& vertexHLSL,
1047 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001048{
1049 if (pixelHLSL.empty() || vertexHLSL.empty())
1050 {
1051 return false;
1052 }
1053
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001054 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1055 bool usesFragColor = fragmentShader->mUsesFragColor;
1056 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001057 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001058 {
1059 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1060 return false;
1061 }
1062
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001063 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001064 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001065 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001066
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001067 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1068
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001069 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1070 // - with a 3.0 context, the output color is copied to channel 0
1071 // - with a 2.0 context, the output color is broadcast to all channels
1072 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1073 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1074
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001075 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001076 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001077 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001078
1079 return false;
1080 }
1081
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001082 vertexShader->resetVaryingsRegisterAssignment();
1083
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001084 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1085 {
1086 bool matched = false;
1087
1088 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1089 {
1090 if (output->name == input->name)
1091 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001092 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001093 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001094 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 +00001095
1096 return false;
1097 }
1098
1099 output->reg = input->reg;
1100 output->col = input->col;
1101
1102 matched = true;
1103 break;
1104 }
1105 }
1106
1107 if (!matched)
1108 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001109 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001110
1111 return false;
1112 }
1113 }
1114
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001115 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001116 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001117 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001118 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1119
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001120 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1121
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001122 // special varyings that use reserved registers
1123 int reservedRegisterIndex = registers;
1124 std::string fragCoordSemantic;
1125 std::string pointCoordSemantic;
1126
1127 if (fragmentShader->mUsesFragCoord)
1128 {
1129 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1130 }
1131
1132 if (fragmentShader->mUsesPointCoord)
1133 {
1134 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1135 // In DX11 we compute this in the GS.
1136 if (shaderModel == 3)
1137 {
1138 pointCoordSemantic = "TEXCOORD0";
1139 }
1140 else if (shaderModel >= 4)
1141 {
1142 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1143 }
1144 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001145
1146 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001147 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001148
1149 int semanticIndex = 0;
1150 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1151 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001152 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001153 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1154
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001155 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001156 }
1157
1158 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001159 "\n"
1160 "struct VS_OUTPUT\n"
1161 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001162
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001163 if (shaderModel < 4)
1164 {
1165 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1166 }
1167
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001168 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001169
1170 if (fragmentShader->mUsesFragCoord)
1171 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001172 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001173 }
1174
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001175 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001176 {
1177 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1178 }
1179
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001180 if (shaderModel >= 4)
1181 {
1182 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1183 }
1184
1185 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001186 "\n"
1187 "VS_OUTPUT main(VS_INPUT input)\n"
1188 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001189
1190 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1191 {
1192 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1193
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001194 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001195 {
1196 vertexHLSL += "transpose";
1197 }
1198
1199 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1200 }
1201
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001202 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1203 {
1204 vertexHLSL += "\n"
1205 " dx_initConstantBuffers();\n";
1206 }
1207
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001208 if (shaderModel >= 4)
1209 {
1210 vertexHLSL += "\n"
1211 " gl_main();\n"
1212 "\n"
1213 " VS_OUTPUT output;\n"
1214 " output.gl_Position.x = gl_Position.x;\n"
1215 " output.gl_Position.y = -gl_Position.y;\n"
1216 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1217 " output.gl_Position.w = gl_Position.w;\n";
1218 }
1219 else
1220 {
1221 vertexHLSL += "\n"
1222 " gl_main();\n"
1223 "\n"
1224 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001225 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1226 " 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 +00001227 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1228 " output.gl_Position.w = gl_Position.w;\n";
1229 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001230
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001231 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001232 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001233 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234 }
1235
1236 if (fragmentShader->mUsesFragCoord)
1237 {
1238 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1239 }
1240
1241 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1242 {
1243 if (varying->reg >= 0)
1244 {
1245 for (int i = 0; i < varying->size; i++)
1246 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001247 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001248
1249 for (int j = 0; j < rows; j++)
1250 {
1251 int r = varying->reg + i * rows + j;
1252 vertexHLSL += " output.v" + str(r);
1253
1254 bool sharedRegister = false; // Register used by multiple varyings
1255
1256 for (int x = 0; x < 4; x++)
1257 {
1258 if (packing[r][x] && packing[r][x] != packing[r][0])
1259 {
1260 sharedRegister = true;
1261 break;
1262 }
1263 }
1264
1265 if(sharedRegister)
1266 {
1267 vertexHLSL += ".";
1268
1269 for (int x = 0; x < 4; x++)
1270 {
1271 if (packing[r][x] == &*varying)
1272 {
1273 switch(x)
1274 {
1275 case 0: vertexHLSL += "x"; break;
1276 case 1: vertexHLSL += "y"; break;
1277 case 2: vertexHLSL += "z"; break;
1278 case 3: vertexHLSL += "w"; break;
1279 }
1280 }
1281 }
1282 }
1283
1284 vertexHLSL += " = " + varying->name;
1285
1286 if (varying->array)
1287 {
1288 vertexHLSL += "[" + str(i) + "]";
1289 }
1290
1291 if (rows > 1)
1292 {
1293 vertexHLSL += "[" + str(j) + "]";
1294 }
1295
1296 vertexHLSL += ";\n";
1297 }
1298 }
1299 }
1300 }
1301
1302 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001303 " return output;\n"
1304 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001305
1306 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001307 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001308
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001309 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310
1311 if (fragmentShader->mUsesFragCoord)
1312 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001313 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001314 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001315
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001316 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1317 {
1318 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1319 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001320
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001321 // Must consume the PSIZE element if the geometry shader is not active
1322 // We won't know if we use a GS until we draw
1323 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1324 {
1325 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1326 }
1327
1328 if (fragmentShader->mUsesFragCoord)
1329 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001330 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001331 {
1332 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1333 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001334 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001335 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001336 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1337 }
1338 }
1339
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001340 pixelHLSL += "};\n"
1341 "\n"
1342 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001343 "{\n";
1344
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001345 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001346 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001347 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001348 }
1349
1350 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001351 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001352
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001353 if (fragmentShader->mUsesFrontFacing)
1354 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001355 if (shaderModel >= 4)
1356 {
1357 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1358 "{\n";
1359 }
1360 else
1361 {
1362 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1363 "{\n";
1364 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001365 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001366 else
1367 {
1368 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1369 "{\n";
1370 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001371
1372 if (fragmentShader->mUsesFragCoord)
1373 {
1374 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1375
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001376 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001377 {
1378 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1379 " gl_FragCoord.y = input.dx_VPos.y;\n";
1380 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001381 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001382 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001383 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001384 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001385 }
1386 else
1387 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001388 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1389 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1390 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001391 }
1392
daniel@transgaming.com12985182012-12-20 20:56:31 +00001393 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001394 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001395 }
1396
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001397 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001398 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001399 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1400 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001401 }
1402
1403 if (fragmentShader->mUsesFrontFacing)
1404 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001405 if (shaderModel <= 3)
1406 {
1407 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1408 }
1409 else
1410 {
1411 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1412 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001413 }
1414
1415 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1416 {
1417 if (varying->reg >= 0)
1418 {
1419 for (int i = 0; i < varying->size; i++)
1420 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001421 GLenum transposedType = TransposeMatrixType(varying->type);
1422 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001423 for (int j = 0; j < rows; j++)
1424 {
1425 std::string n = str(varying->reg + i * rows + j);
1426 pixelHLSL += " " + varying->name;
1427
1428 if (varying->array)
1429 {
1430 pixelHLSL += "[" + str(i) + "]";
1431 }
1432
1433 if (rows > 1)
1434 {
1435 pixelHLSL += "[" + str(j) + "]";
1436 }
1437
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001438 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001439 {
1440 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1441 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1442 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1443 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1444 default: UNREACHABLE();
1445 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001446 }
1447 }
1448 }
1449 else UNREACHABLE();
1450 }
1451
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001452 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1453 {
1454 pixelHLSL += "\n"
1455 " dx_initConstantBuffers();\n";
1456 }
1457
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001459 " gl_main();\n"
1460 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001461 " PS_OUTPUT output;\n";
1462
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001463 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001464 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001465 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001466
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001467 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001468 }
1469
1470 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001471 " return output;\n"
1472 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001473
1474 return true;
1475}
1476
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001477std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1478{
1479 std::string varyingHLSL;
1480
1481 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1482 {
1483 if (varying->reg >= 0)
1484 {
1485 for (int i = 0; i < varying->size; i++)
1486 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001487 GLenum transposedType = TransposeMatrixType(varying->type);
1488 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001489 for (int j = 0; j < rows; j++)
1490 {
1491 switch (varying->interpolation)
1492 {
1493 case Smooth: varyingHLSL += " "; break;
1494 case Flat: varyingHLSL += " nointerpolation "; break;
1495 case Centroid: varyingHLSL += " centroid "; break;
1496 default: UNREACHABLE();
1497 }
1498
1499 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001500
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001501 varyingHLSL += "float" + str(VariableColumnCount(transposedType)) + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001502 }
1503 }
1504 }
1505 else UNREACHABLE();
1506 }
1507
1508 return varyingHLSL;
1509}
1510
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001511bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1512{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001513 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001514
1515 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001516 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001517 if (format != GL_PROGRAM_BINARY_ANGLE)
1518 {
1519 infoLog.append("Invalid program binary format.");
1520 return false;
1521 }
1522
1523 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001524 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001525 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001526 {
1527 infoLog.append("Invalid program binary version.");
1528 return false;
1529 }
1530
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001531 int compileFlags = 0;
1532 stream.read(&compileFlags);
1533 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1534 {
1535 infoLog.append("Mismatched compilation flags.");
1536 return false;
1537 }
1538
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001539 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1540 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001541 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001542 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001543 stream.read(&name);
1544 mLinkedAttribute[i].name = name;
1545 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001546 }
1547
1548 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1549 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001550 stream.read(&mSamplersPS[i].active);
1551 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001552
1553 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001554 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555 mSamplersPS[i].textureType = (TextureType) textureType;
1556 }
1557
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001558 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001559 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001560 stream.read(&mSamplersVS[i].active);
1561 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001562
1563 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001564 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565 mSamplersVS[i].textureType = (TextureType) textureType;
1566 }
1567
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001568 stream.read(&mUsedVertexSamplerRange);
1569 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001570 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001571 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001572
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001573 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001574 stream.read(&size);
1575 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001576 {
1577 infoLog.append("Invalid program binary.");
1578 return false;
1579 }
1580
1581 mUniforms.resize(size);
1582 for (unsigned int i = 0; i < size; ++i)
1583 {
1584 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001585 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001586 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001587 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001588 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001589
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001590 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001591 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001592 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001593 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001594 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001595
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001596 int offset;
1597 int arrayStride;
1598 int matrixStride;
1599 bool isRowMajorMatrix;
1600
1601 stream.read(&offset);
1602 stream.read(&arrayStride);
1603 stream.read(&matrixStride);
1604 stream.read(&isRowMajorMatrix);
1605
1606 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1607
1608 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001609
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001610 stream.read(&mUniforms[i]->psRegisterIndex);
1611 stream.read(&mUniforms[i]->vsRegisterIndex);
1612 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001613 }
1614
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001615 stream.read(&size);
1616 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617 {
1618 infoLog.append("Invalid program binary.");
1619 return false;
1620 }
1621
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001622 mUniformBlocks.resize(size);
1623 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1624 {
1625 std::string name;
1626 unsigned int elementIndex;
1627 unsigned int dataSize;
1628
1629 stream.read(&name);
1630 stream.read(&elementIndex);
1631 stream.read(&dataSize);
1632
1633 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1634
1635 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1636 stream.read(&uniformBlock.psRegisterIndex);
1637 stream.read(&uniformBlock.vsRegisterIndex);
1638
1639 size_t numMembers;
1640 stream.read(&numMembers);
1641 uniformBlock.memberUniformIndexes.resize(numMembers);
1642 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1643 {
1644 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1645 }
1646 }
1647
1648 stream.read(&size);
1649 if (stream.error())
1650 {
1651 infoLog.append("Invalid program binary.");
1652 return false;
1653 }
1654
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 mUniformIndex.resize(size);
1656 for (unsigned int i = 0; i < size; ++i)
1657 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001658 stream.read(&mUniformIndex[i].name);
1659 stream.read(&mUniformIndex[i].element);
1660 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661 }
1662
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001663 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665
1666 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001669 unsigned int geometryShaderSize;
1670 stream.read(&geometryShaderSize);
1671
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
daniel@transgaming.com36038542012-11-28 20:59:26 +00001674 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 ptr += sizeof(GUID);
1676
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001677 GUID identifier = mRenderer->getAdapterIdentifier();
1678 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 {
1680 infoLog.append("Invalid program binary.");
1681 return false;
1682 }
1683
1684 const char *pixelShaderFunction = ptr;
1685 ptr += pixelShaderSize;
1686
1687 const char *vertexShaderFunction = ptr;
1688 ptr += vertexShaderSize;
1689
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001690 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1691 ptr += geometryShaderSize;
1692
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001693 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001694 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001695 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696 {
1697 infoLog.append("Could not create pixel shader.");
1698 return false;
1699 }
1700
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001701 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001702 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001703 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704 {
1705 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001706 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001707 mPixelExecutable = NULL;
1708 return false;
1709 }
1710
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001711 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1712 {
1713 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1714 geometryShaderSize, rx::SHADER_GEOMETRY);
1715 if (!mGeometryExecutable)
1716 {
1717 infoLog.append("Could not create geometry shader.");
1718 delete mPixelExecutable;
1719 mPixelExecutable = NULL;
1720 delete mVertexExecutable;
1721 mVertexExecutable = NULL;
1722 return false;
1723 }
1724 }
1725 else
1726 {
1727 mGeometryExecutable = NULL;
1728 }
1729
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001730 return true;
1731}
1732
1733bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1734{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001735 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001737 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001738 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001739 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
1741 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1742 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 stream.write(mLinkedAttribute[i].type);
1744 stream.write(mLinkedAttribute[i].name);
1745 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746 }
1747
1748 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1749 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001750 stream.write(mSamplersPS[i].active);
1751 stream.write(mSamplersPS[i].logicalTextureUnit);
1752 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001753 }
1754
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001755 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001756 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001757 stream.write(mSamplersVS[i].active);
1758 stream.write(mSamplersVS[i].logicalTextureUnit);
1759 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760 }
1761
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001762 stream.write(mUsedVertexSamplerRange);
1763 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001764 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001765 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001766
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001768 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001770 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001772 stream.write(uniform.type);
1773 stream.write(uniform.precision);
1774 stream.write(uniform.name);
1775 stream.write(uniform.arraySize);
1776 stream.write(uniform.blockIndex);
1777
1778 stream.write(uniform.blockInfo.offset);
1779 stream.write(uniform.blockInfo.arrayStride);
1780 stream.write(uniform.blockInfo.matrixStride);
1781 stream.write(uniform.blockInfo.isRowMajorMatrix);
1782
1783 stream.write(uniform.psRegisterIndex);
1784 stream.write(uniform.vsRegisterIndex);
1785 stream.write(uniform.registerCount);
1786 }
1787
1788 stream.write(mUniformBlocks.size());
1789 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1790 {
1791 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1792
1793 stream.write(uniformBlock.name);
1794 stream.write(uniformBlock.elementIndex);
1795 stream.write(uniformBlock.dataSize);
1796
1797 stream.write(uniformBlock.memberUniformIndexes.size());
1798 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1799 {
1800 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1801 }
1802
1803 stream.write(uniformBlock.psRegisterIndex);
1804 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805 }
1806
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001807 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1809 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001810 stream.write(mUniformIndex[i].name);
1811 stream.write(mUniformIndex[i].element);
1812 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 }
1814
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001815 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001818 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001819 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001821 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1822 stream.write(geometryShaderSize);
1823
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001824 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001826 GLsizei streamLength = stream.length();
1827 const void *streamData = stream.data();
1828
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001829 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001830 if (totalLength > bufSize)
1831 {
1832 if (length)
1833 {
1834 *length = 0;
1835 }
1836
1837 return false;
1838 }
1839
1840 if (binary)
1841 {
1842 char *ptr = (char*) binary;
1843
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001844 memcpy(ptr, streamData, streamLength);
1845 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001846
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001847 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001848 ptr += sizeof(GUID);
1849
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001850 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001851 ptr += pixelShaderSize;
1852
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001853 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854 ptr += vertexShaderSize;
1855
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001856 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1857 {
1858 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1859 ptr += geometryShaderSize;
1860 }
1861
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001862 ASSERT(ptr - totalLength == binary);
1863 }
1864
1865 if (length)
1866 {
1867 *length = totalLength;
1868 }
1869
1870 return true;
1871}
1872
1873GLint ProgramBinary::getLength()
1874{
1875 GLint length;
1876 if (save(NULL, INT_MAX, &length))
1877 {
1878 return length;
1879 }
1880 else
1881 {
1882 return 0;
1883 }
1884}
1885
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001886bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001887{
1888 if (!fragmentShader || !fragmentShader->isCompiled())
1889 {
1890 return false;
1891 }
1892
1893 if (!vertexShader || !vertexShader->isCompiled())
1894 {
1895 return false;
1896 }
1897
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001898 mShaderVersion = vertexShader->getShaderVersion();
1899
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001900 std::string pixelHLSL = fragmentShader->getHLSL();
1901 std::string vertexHLSL = vertexShader->getHLSL();
1902
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001903 // Map the varyings to the register file
1904 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1905 int registers = packVaryings(infoLog, packing, fragmentShader);
1906
1907 if (registers < 0)
1908 {
1909 return false;
1910 }
1911
1912 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001913 {
1914 return false;
1915 }
1916
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001917 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001918 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1919 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001920
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001921 if (usesGeometryShader())
1922 {
1923 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1924 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1925 }
1926
1927 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001928 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001929 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001930 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001931
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001932 delete mVertexExecutable;
1933 mVertexExecutable = NULL;
1934 delete mPixelExecutable;
1935 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001936 delete mGeometryExecutable;
1937 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001938 }
1939
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001940 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1941 {
1942 success = false;
1943 }
1944
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001945 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001946 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001947 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001948 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001949
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001950 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1951 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1952 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001953 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1954 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1955 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 +00001956 }
1957
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001958 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1959 {
1960 success = false;
1961 }
1962
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001963 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001964}
1965
1966// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001967bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001968{
1969 unsigned int usedLocations = 0;
1970
1971 // Link attributes that have a binding location
1972 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1973 {
1974 int location = attributeBindings.getAttributeBinding(attribute->name);
1975
1976 if (location != -1) // Set by glBindAttribLocation
1977 {
1978 if (!mLinkedAttribute[location].name.empty())
1979 {
1980 // Multiple active attributes bound to the same location; not an error
1981 }
1982
1983 mLinkedAttribute[location] = *attribute;
1984
1985 int rows = VariableRowCount(attribute->type);
1986
1987 if (rows + location > MAX_VERTEX_ATTRIBS)
1988 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001989 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 +00001990
1991 return false;
1992 }
1993
1994 for (int i = 0; i < rows; i++)
1995 {
1996 usedLocations |= 1 << (location + i);
1997 }
1998 }
1999 }
2000
2001 // Link attributes that don't have a binding location
2002 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2003 {
2004 int location = attributeBindings.getAttributeBinding(attribute->name);
2005
2006 if (location == -1) // Not set by glBindAttribLocation
2007 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002008 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002009 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2010
2011 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2012 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002013 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002014
2015 return false; // Fail to link
2016 }
2017
2018 mLinkedAttribute[availableIndex] = *attribute;
2019 }
2020 }
2021
2022 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2023 {
2024 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002025 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002026
2027 for (int r = 0; r < rows; r++)
2028 {
2029 mSemanticIndex[attributeIndex++] = index++;
2030 }
2031 }
2032
2033 return true;
2034}
2035
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002036bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2037{
2038 if (vertexUniform.type != fragmentUniform.type)
2039 {
2040 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2041 return false;
2042 }
2043 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2044 {
2045 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2046 return false;
2047 }
2048 else if (vertexUniform.precision != fragmentUniform.precision)
2049 {
2050 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2051 return false;
2052 }
2053 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2054 {
2055 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2056 }
2057
2058 const unsigned int numMembers = vertexUniform.fields.size();
2059 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2060 {
2061 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2062 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2063
2064 if (vertexMember.name != fragmentMember.name)
2065 {
2066 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2067 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2068 return false;
2069 }
2070
2071 const std::string memberName = uniformName + "." + vertexUniform.name;
2072 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2073 {
2074 return false;
2075 }
2076 }
2077
2078 return true;
2079}
2080
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002081bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002083 // Check that uniforms defined in the vertex and fragment shaders are identical
2084 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2085 UniformMap linkedUniforms;
2086
2087 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2088 {
2089 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2090 linkedUniforms[vertexUniform.name] = &vertexUniform;
2091 }
2092
2093 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2094 {
2095 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2096 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2097 if (entry != linkedUniforms.end())
2098 {
2099 const sh::Uniform &vertexUniform = *entry->second;
2100 const std::string &uniformName = "uniform " + vertexUniform.name;
2101 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2102 {
2103 return false;
2104 }
2105 }
2106 }
2107
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002108 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002109 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002110 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111 {
2112 return false;
2113 }
2114 }
2115
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002116 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002117 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002118 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002119 {
2120 return false;
2121 }
2122 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002123
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002124 return true;
2125}
2126
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002127int totalRegisterCount(const sh::Uniform &uniform)
2128{
2129 int registerCount = 0;
2130
2131 if (!uniform.fields.empty())
2132 {
2133 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2134 {
2135 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2136 }
2137 }
2138 else
2139 {
2140 registerCount = 1;
2141 }
2142
2143 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2144}
2145
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002146bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002147{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002148 if (!constant.fields.empty())
2149 {
2150 if (constant.arraySize > 0)
2151 {
2152 unsigned int elementRegisterIndex = constant.registerIndex;
2153
2154 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2155 {
2156 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2157 {
2158 const sh::Uniform &field = constant.fields[fieldIndex];
2159 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2160 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2161 if (!defineUniform(shader, fieldUniform, infoLog))
2162 {
2163 return false;
2164 }
2165 elementRegisterIndex += totalRegisterCount(field);
2166 }
2167 }
2168 }
2169 else
2170 {
2171 unsigned int fieldRegisterIndex = constant.registerIndex;
2172
2173 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2174 {
2175 const sh::Uniform &field = constant.fields[fieldIndex];
2176 const std::string &uniformName = constant.name + "." + field.name;
2177
2178 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2179 fieldUniform.fields = field.fields;
2180
2181 if (!defineUniform(shader, fieldUniform, infoLog))
2182 {
2183 return false;
2184 }
2185 fieldRegisterIndex += totalRegisterCount(field);
2186 }
2187 }
2188
2189 return true;
2190 }
2191
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002192 if (constant.type == GL_SAMPLER_2D ||
2193 constant.type == GL_SAMPLER_CUBE)
2194 {
2195 unsigned int samplerIndex = constant.registerIndex;
2196
2197 do
2198 {
2199 if (shader == GL_VERTEX_SHADER)
2200 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002201 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002202 {
2203 mSamplersVS[samplerIndex].active = true;
2204 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2205 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2206 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2207 }
2208 else
2209 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002210 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002211 return false;
2212 }
2213 }
2214 else if (shader == GL_FRAGMENT_SHADER)
2215 {
2216 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2217 {
2218 mSamplersPS[samplerIndex].active = true;
2219 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2220 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2221 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2222 }
2223 else
2224 {
2225 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2226 return false;
2227 }
2228 }
2229 else UNREACHABLE();
2230
2231 samplerIndex++;
2232 }
2233 while (samplerIndex < constant.registerIndex + constant.arraySize);
2234 }
2235
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002236 Uniform *uniform = NULL;
2237 GLint location = getUniformLocation(constant.name);
2238
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002239 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002240 {
2241 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002242 }
2243 else
2244 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002245 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002246 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002247
2248 if (!uniform)
2249 {
2250 return false;
2251 }
2252
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002253 if (shader == GL_FRAGMENT_SHADER)
2254 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002255 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002256 }
2257 else if (shader == GL_VERTEX_SHADER)
2258 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002259 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002260 }
2261 else UNREACHABLE();
2262
2263 if (location >= 0)
2264 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002265 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002266 }
2267
2268 mUniforms.push_back(uniform);
2269 unsigned int uniformIndex = mUniforms.size() - 1;
2270
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002271 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002272 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002273 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002274 }
2275
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002276 if (shader == GL_VERTEX_SHADER)
2277 {
2278 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2279 {
2280 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2281 return false;
2282 }
2283 }
2284 else if (shader == GL_FRAGMENT_SHADER)
2285 {
2286 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2287 {
2288 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2289 return false;
2290 }
2291 }
2292 else UNREACHABLE();
2293
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002294 return true;
2295}
2296
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002297bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2298{
2299 const char* blockName = vertexInterfaceBlock.name.c_str();
2300
2301 // validate blocks for the same member types
2302 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2303 {
2304 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2305 return false;
2306 }
2307
2308 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2309 {
2310 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2311 return false;
2312 }
2313
2314 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2315 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2316 {
2317 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2318 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2319
2320 if (vertexMember.name != fragmentMember.name)
2321 {
2322 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2323 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2324 return false;
2325 }
2326
2327 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2328 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2329 {
2330 return false;
2331 }
2332 }
2333
2334 return true;
2335}
2336
2337bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2338{
2339 // Check that interface blocks defined in the vertex and fragment shaders are identical
2340 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2341 UniformBlockMap linkedUniformBlocks;
2342
2343 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2344 {
2345 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2346 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2347 }
2348
2349 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2350 {
2351 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2352 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2353 if (entry != linkedUniformBlocks.end())
2354 {
2355 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2356 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2357 {
2358 return false;
2359 }
2360 }
2361 }
2362
2363 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2364 {
2365 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2366 {
2367 return false;
2368 }
2369 }
2370
2371 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2372 {
2373 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2374 {
2375 return false;
2376 }
2377 }
2378
2379 return true;
2380}
2381
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002382void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2383{
2384 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2385 {
2386 const sh::Uniform &uniform = uniforms[uniformIndex];
2387
2388 if (!uniform.fields.empty())
2389 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002390 if (uniform.arraySize > 0)
2391 {
2392 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2393 {
2394 const std::string uniformElementName = uniform.name + "[" + str(arrayElement) + "]";
2395 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2396 }
2397 }
2398 else
2399 {
2400 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2401 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002402 }
2403 else
2404 {
2405 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2406 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2407 blockIndex, **blockInfoItr);
2408
2409 // add to uniform list, but not index, since uniform block uniforms have no location
2410 blockUniformIndexes->push_back(mUniforms.size());
2411 mUniforms.push_back(newUniform);
2412 (*blockInfoItr)++;
2413 }
2414 }
2415}
2416
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002417bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2418{
2419 // create uniform block entries if they do not exist
2420 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2421 {
2422 std::vector<unsigned int> blockUniformIndexes;
2423 const unsigned int blockIndex = mUniformBlocks.size();
2424
2425 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002426 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2427 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002428
2429 // create all the uniform blocks
2430 if (interfaceBlock.arraySize > 0)
2431 {
2432 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2433 {
2434 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2435 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2436 mUniformBlocks.push_back(newUniformBlock);
2437 }
2438 }
2439 else
2440 {
2441 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2442 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2443 mUniformBlocks.push_back(newUniformBlock);
2444 }
2445 }
2446
2447 // Assign registers to the uniform blocks
2448 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2449 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2450 ASSERT(blockIndex != GL_INVALID_INDEX);
2451 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2452
2453 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2454 {
2455 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2456 ASSERT(uniformBlock->name == interfaceBlock.name);
2457
2458 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2459 {
2460 return false;
2461 }
2462 }
2463
2464 return true;
2465}
2466
2467bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2468{
2469 if (shader == GL_VERTEX_SHADER)
2470 {
2471 uniformBlock->vsRegisterIndex = registerIndex;
2472 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2473
2474 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2475 {
2476 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2477 return false;
2478 }
2479 }
2480 else if (shader == GL_FRAGMENT_SHADER)
2481 {
2482 uniformBlock->psRegisterIndex = registerIndex;
2483 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2484
2485 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2486 {
2487 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2488 return false;
2489 }
2490 }
2491 else UNREACHABLE();
2492
2493 return true;
2494}
2495
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002496std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2497{
2498 // for now we only handle point sprite emulation
2499 ASSERT(usesPointSpriteEmulation());
2500 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2501}
2502
2503std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2504{
2505 ASSERT(registers >= 0);
2506 ASSERT(vertexShader->mUsesPointSize);
2507 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2508
2509 std::string geomHLSL;
2510
2511 std::string varyingSemantic = "TEXCOORD";
2512
2513 std::string fragCoordSemantic;
2514 std::string pointCoordSemantic;
2515
2516 int reservedRegisterIndex = registers;
2517
2518 if (fragmentShader->mUsesFragCoord)
2519 {
2520 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2521 }
2522
2523 if (fragmentShader->mUsesPointCoord)
2524 {
2525 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2526 }
2527
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002528 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2529 "\n"
2530 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002531 "{\n";
2532
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002533 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002534
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002535 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002536
2537 if (fragmentShader->mUsesFragCoord)
2538 {
2539 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2540 }
2541
2542 geomHLSL += " float gl_PointSize : PSIZE;\n"
2543 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002544 "};\n"
2545 "\n"
2546 "struct GS_OUTPUT\n"
2547 "{\n";
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 if (fragmentShader->mUsesPointCoord)
2557 {
2558 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2559 }
2560
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002561 geomHLSL += " float gl_PointSize : PSIZE;\n"
2562 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002563 "};\n"
2564 "\n"
2565 "static float2 pointSpriteCorners[] = \n"
2566 "{\n"
2567 " float2( 0.5f, -0.5f),\n"
2568 " float2( 0.5f, 0.5f),\n"
2569 " float2(-0.5f, -0.5f),\n"
2570 " float2(-0.5f, 0.5f)\n"
2571 "};\n"
2572 "\n"
2573 "static float2 pointSpriteTexcoords[] = \n"
2574 "{\n"
2575 " float2(1.0f, 1.0f),\n"
2576 " float2(1.0f, 0.0f),\n"
2577 " float2(0.0f, 1.0f),\n"
2578 " float2(0.0f, 0.0f)\n"
2579 "};\n"
2580 "\n"
2581 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2582 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2583 "\n"
2584 "[maxvertexcount(4)]\n"
2585 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2586 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002587 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2588 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002589
2590 for (int r = 0; r < registers; r++)
2591 {
2592 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2593 }
2594
2595 if (fragmentShader->mUsesFragCoord)
2596 {
2597 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2598 }
2599
2600 geomHLSL += " \n"
2601 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2602 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002603 " 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 +00002604
2605 for (int corner = 0; corner < 4; corner++)
2606 {
2607 geomHLSL += " \n"
2608 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2609
2610 if (fragmentShader->mUsesPointCoord)
2611 {
2612 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2613 }
2614
2615 geomHLSL += " outStream.Append(output);\n";
2616 }
2617
2618 geomHLSL += " \n"
2619 " outStream.RestartStrip();\n"
2620 "}\n";
2621
2622 return geomHLSL;
2623}
2624
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002625// This method needs to match OutputHLSL::decorate
2626std::string ProgramBinary::decorateAttribute(const std::string &name)
2627{
2628 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2629 {
2630 return "_" + name;
2631 }
2632
2633 return name;
2634}
2635
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002636bool ProgramBinary::isValidated() const
2637{
2638 return mValidated;
2639}
2640
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002641void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002642{
2643 // Skip over inactive attributes
2644 unsigned int activeAttribute = 0;
2645 unsigned int attribute;
2646 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2647 {
2648 if (mLinkedAttribute[attribute].name.empty())
2649 {
2650 continue;
2651 }
2652
2653 if (activeAttribute == index)
2654 {
2655 break;
2656 }
2657
2658 activeAttribute++;
2659 }
2660
2661 if (bufsize > 0)
2662 {
2663 const char *string = mLinkedAttribute[attribute].name.c_str();
2664
2665 strncpy(name, string, bufsize);
2666 name[bufsize - 1] = '\0';
2667
2668 if (length)
2669 {
2670 *length = strlen(name);
2671 }
2672 }
2673
2674 *size = 1; // Always a single 'type' instance
2675
2676 *type = mLinkedAttribute[attribute].type;
2677}
2678
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002679GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002680{
2681 int count = 0;
2682
2683 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2684 {
2685 if (!mLinkedAttribute[attributeIndex].name.empty())
2686 {
2687 count++;
2688 }
2689 }
2690
2691 return count;
2692}
2693
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002694GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002695{
2696 int maxLength = 0;
2697
2698 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2699 {
2700 if (!mLinkedAttribute[attributeIndex].name.empty())
2701 {
2702 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2703 }
2704 }
2705
2706 return maxLength;
2707}
2708
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002709void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002710{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002711 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002712
2713 if (bufsize > 0)
2714 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002715 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002716
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002717 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002718 {
2719 string += "[0]";
2720 }
2721
2722 strncpy(name, string.c_str(), bufsize);
2723 name[bufsize - 1] = '\0';
2724
2725 if (length)
2726 {
2727 *length = strlen(name);
2728 }
2729 }
2730
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002731 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002732
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002733 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002734}
2735
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002736GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002737{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002738 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002739}
2740
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002741GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002742{
2743 int maxLength = 0;
2744
2745 unsigned int numUniforms = mUniforms.size();
2746 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2747 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002748 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002749 {
2750 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2751 if (mUniforms[uniformIndex]->isArray())
2752 {
2753 length += 3; // Counting in "[0]".
2754 }
2755 maxLength = std::max(length, maxLength);
2756 }
2757 }
2758
2759 return maxLength;
2760}
2761
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002762GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2763{
2764 const gl::Uniform& uniform = *mUniforms[index];
2765
2766 switch (pname)
2767 {
2768 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2769 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002770 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 +00002771 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002772
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002773 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2774 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2775 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2776 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002777
2778 default:
2779 UNREACHABLE();
2780 break;
2781 }
2782 return 0;
2783}
2784
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002785void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2786{
2787 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2788
2789 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2790
2791 if (bufSize > 0)
2792 {
2793 std::string string = uniformBlock.name;
2794
2795 if (uniformBlock.isArrayElement())
2796 {
2797 string += "[" + str(uniformBlock.elementIndex) + "]";
2798 }
2799
2800 strncpy(uniformBlockName, string.c_str(), bufSize);
2801 uniformBlockName[bufSize - 1] = '\0';
2802
2803 if (length)
2804 {
2805 *length = strlen(uniformBlockName);
2806 }
2807 }
2808}
2809
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002810void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2811{
2812 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2813
2814 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2815
2816 switch (pname)
2817 {
2818 case GL_UNIFORM_BLOCK_DATA_SIZE:
2819 *params = static_cast<GLint>(uniformBlock.dataSize);
2820 break;
2821 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002822 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002823 break;
2824 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2825 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2826 break;
2827 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2828 {
2829 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2830 {
2831 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2832 }
2833 }
2834 break;
2835 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2836 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2837 break;
2838 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2839 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2840 break;
2841 default: UNREACHABLE();
2842 }
2843}
2844
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002845GLuint ProgramBinary::getActiveUniformBlockCount() const
2846{
2847 return mUniformBlocks.size();
2848}
2849
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002850GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2851{
2852 unsigned int maxLength = 0;
2853
2854 unsigned int numUniformBlocks = mUniformBlocks.size();
2855 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2856 {
2857 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2858 if (!uniformBlock.name.empty())
2859 {
2860 const unsigned int length = uniformBlock.name.length() + 1;
2861
2862 // Counting in "[0]".
2863 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2864
2865 maxLength = std::max(length + arrayLength, maxLength);
2866 }
2867 }
2868
2869 return maxLength;
2870}
2871
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002872void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002873{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002874 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002875 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002876 {
2877 mValidated = false;
2878 }
2879 else
2880 {
2881 mValidated = true;
2882 }
2883}
2884
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002885bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002886{
2887 // if any two active samplers in a program are of different types, but refer to the same
2888 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2889 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2890
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002891 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002892 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002893
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002894 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002895 {
2896 textureUnitType[i] = TEXTURE_UNKNOWN;
2897 }
2898
2899 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2900 {
2901 if (mSamplersPS[i].active)
2902 {
2903 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2904
2905 if (unit >= maxCombinedTextureImageUnits)
2906 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002907 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002908 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002909 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002910 }
2911
2912 return false;
2913 }
2914
2915 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2916 {
2917 if (mSamplersPS[i].textureType != textureUnitType[unit])
2918 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002919 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002920 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002921 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002922 }
2923
2924 return false;
2925 }
2926 }
2927 else
2928 {
2929 textureUnitType[unit] = mSamplersPS[i].textureType;
2930 }
2931 }
2932 }
2933
2934 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2935 {
2936 if (mSamplersVS[i].active)
2937 {
2938 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2939
2940 if (unit >= maxCombinedTextureImageUnits)
2941 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002942 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002943 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002944 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002945 }
2946
2947 return false;
2948 }
2949
2950 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2951 {
2952 if (mSamplersVS[i].textureType != textureUnitType[unit])
2953 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002954 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002955 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002956 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002957 }
2958
2959 return false;
2960 }
2961 }
2962 else
2963 {
2964 textureUnitType[unit] = mSamplersVS[i].textureType;
2965 }
2966 }
2967 }
2968
2969 return true;
2970}
2971
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002972ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2973{
2974}
2975
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002976struct AttributeSorter
2977{
2978 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2979 : originalIndices(semanticIndices)
2980 {
2981 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2982 {
2983 indices[i] = i;
2984 }
2985
2986 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2987 }
2988
2989 bool operator()(int a, int b)
2990 {
2991 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2992 }
2993
2994 int indices[MAX_VERTEX_ATTRIBS];
2995 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2996};
2997
2998void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2999{
3000 AttributeSorter sorter(mSemanticIndex);
3001
3002 int oldIndices[MAX_VERTEX_ATTRIBS];
3003 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3004
3005 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3006 {
3007 oldIndices[i] = mSemanticIndex[i];
3008 oldTranslatedAttributes[i] = attributes[i];
3009 }
3010
3011 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3012 {
3013 int oldIndex = sorter.indices[i];
3014 sortedSemanticIndices[i] = oldIndices[oldIndex];
3015 attributes[i] = oldTranslatedAttributes[oldIndex];
3016 }
3017}
3018
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003019}