blob: b05016717132a006d3ba85a87ab752376e636ae5 [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"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "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"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000025
daniel@transgaming.com88853c52012-12-20 20:56:40 +000026#undef near
27#undef far
28
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029namespace gl
30{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031std::string str(int i)
32{
33 char buffer[20];
34 snprintf(buffer, sizeof(buffer), "%d", i);
35 return buffer;
36}
37
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000038namespace
39{
40
41unsigned int parseAndStripArrayIndex(std::string* name)
42{
43 unsigned int subscript = GL_INVALID_INDEX;
44
45 // Strip any trailing array operator and retrieve the subscript
46 size_t open = name->find_last_of('[');
47 size_t close = name->find_last_of(']');
48 if (open != std::string::npos && close == name->length() - 1)
49 {
50 subscript = atoi(name->substr(open + 1).c_str());
51 name->erase(open);
52 }
53
54 return subscript;
55}
56
57}
58
daniel@transgaming.comdb019952012-12-20 21:13:32 +000059UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
60 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000061{
62}
63
daniel@transgaming.come87ca002012-07-24 18:30:43 +000064unsigned int ProgramBinary::mCurrentSerial = 1;
65
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000066ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000067{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000068 mPixelExecutable = NULL;
69 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000070 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000072 mValidated = false;
73
74 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
75 {
76 mSemanticIndex[index] = -1;
77 }
78
79 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
80 {
81 mSamplersPS[index].active = false;
82 }
83
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000084 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000085 {
86 mSamplersVS[index].active = false;
87 }
88
89 mUsedVertexSamplerRange = 0;
90 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000091 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000092}
93
94ProgramBinary::~ProgramBinary()
95{
daniel@transgaming.com95892412012-11-28 20:59:09 +000096 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000097 mPixelExecutable = NULL;
98
daniel@transgaming.com95892412012-11-28 20:59:09 +000099 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000100 mVertexExecutable = NULL;
101
102 delete mGeometryExecutable;
103 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000104
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000105 while (!mUniforms.empty())
106 {
107 delete mUniforms.back();
108 mUniforms.pop_back();
109 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000110
111 while (!mUniformBlocks.empty())
112 {
113 delete mUniformBlocks.back();
114 mUniformBlocks.pop_back();
115 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116}
117
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000118unsigned int ProgramBinary::getSerial() const
119{
120 return mSerial;
121}
122
123unsigned int ProgramBinary::issueSerial()
124{
125 return mCurrentSerial++;
126}
127
daniel@transgaming.com95892412012-11-28 20:59:09 +0000128rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000129{
130 return mPixelExecutable;
131}
132
daniel@transgaming.com95892412012-11-28 20:59:09 +0000133rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000134{
135 return mVertexExecutable;
136}
137
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000138rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
139{
140 return mGeometryExecutable;
141}
142
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000143GLuint ProgramBinary::getAttributeLocation(const char *name)
144{
145 if (name)
146 {
147 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
148 {
149 if (mLinkedAttribute[index].name == std::string(name))
150 {
151 return index;
152 }
153 }
154 }
155
156 return -1;
157}
158
159int ProgramBinary::getSemanticIndex(int attributeIndex)
160{
161 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
162
163 return mSemanticIndex[attributeIndex];
164}
165
166// Returns one more than the highest sampler index used.
167GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
168{
169 switch (type)
170 {
171 case SAMPLER_PIXEL:
172 return mUsedPixelSamplerRange;
173 case SAMPLER_VERTEX:
174 return mUsedVertexSamplerRange;
175 default:
176 UNREACHABLE();
177 return 0;
178 }
179}
180
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000181bool ProgramBinary::usesPointSize() const
182{
183 return mUsesPointSize;
184}
185
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000186bool ProgramBinary::usesPointSpriteEmulation() const
187{
188 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
189}
190
191bool ProgramBinary::usesGeometryShader() const
192{
193 return usesPointSpriteEmulation();
194}
195
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000196// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
197// index (0-15 for the pixel shader and 0-3 for the vertex shader).
198GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
199{
200 GLint logicalTextureUnit = -1;
201
202 switch (type)
203 {
204 case SAMPLER_PIXEL:
205 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
206
207 if (mSamplersPS[samplerIndex].active)
208 {
209 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
210 }
211 break;
212 case SAMPLER_VERTEX:
213 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
214
215 if (mSamplersVS[samplerIndex].active)
216 {
217 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
218 }
219 break;
220 default: UNREACHABLE();
221 }
222
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000223 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000224 {
225 return logicalTextureUnit;
226 }
227
228 return -1;
229}
230
231// Returns the texture type for a given Direct3D 9 sampler type and
232// index (0-15 for the pixel shader and 0-3 for the vertex shader).
233TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
234{
235 switch (type)
236 {
237 case SAMPLER_PIXEL:
238 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
239 ASSERT(mSamplersPS[samplerIndex].active);
240 return mSamplersPS[samplerIndex].textureType;
241 case SAMPLER_VERTEX:
242 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
243 ASSERT(mSamplersVS[samplerIndex].active);
244 return mSamplersVS[samplerIndex].textureType;
245 default: UNREACHABLE();
246 }
247
248 return TEXTURE_2D;
249}
250
251GLint ProgramBinary::getUniformLocation(std::string name)
252{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000253 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000254
255 unsigned int numUniforms = mUniformIndex.size();
256 for (unsigned int location = 0; location < numUniforms; location++)
257 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000258 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000259 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000260 const int index = mUniformIndex[location].index;
261 const bool isArray = mUniforms[index]->isArray();
262
263 if ((isArray && mUniformIndex[location].element == subscript) ||
264 (subscript == GL_INVALID_INDEX))
265 {
266 return location;
267 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000268 }
269 }
270
271 return -1;
272}
273
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000274GLuint ProgramBinary::getUniformIndex(std::string name)
275{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000276 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000277
278 // The app is not allowed to specify array indices other than 0 for arrays of basic types
279 if (subscript != 0 && subscript != GL_INVALID_INDEX)
280 {
281 return GL_INVALID_INDEX;
282 }
283
284 unsigned int numUniforms = mUniforms.size();
285 for (unsigned int index = 0; index < numUniforms; index++)
286 {
287 if (mUniforms[index]->name == name)
288 {
289 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
290 {
291 return index;
292 }
293 }
294 }
295
296 return GL_INVALID_INDEX;
297}
298
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000299template <typename T>
300bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000301{
302 if (location < 0 || location >= (int)mUniformIndex.size())
303 {
304 return false;
305 }
306
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000307 const int components = UniformComponentCount(targetUniformType);
308 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
309
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000310 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
311 targetUniform->dirty = true;
312
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000313 int elementCount = targetUniform->elementCount();
314
315 if (elementCount == 1 && count > 1)
316 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
317
318 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
319
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000320 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000321 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000322 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000323
324 for (int i = 0; i < count; i++)
325 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000326 for (int c = 0; c < components; c++)
327 {
328 target[c] = v[c];
329 }
330 for (int c = components; c < 4; c++)
331 {
332 target[c] = 0;
333 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000334 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000335 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000336 }
337 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000338 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000339 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000340 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000341
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000342 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000343 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000344 for (int c = 0; c < components; c++)
345 {
346 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
347 }
348 for (int c = components; c < 4; c++)
349 {
350 boolParams[c] = GL_FALSE;
351 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000352 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000353 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000354 }
355 }
356 else
357 {
358 return false;
359 }
360
361 return true;
362}
363
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000364bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
365{
366 return setUniform(location, count, v, GL_FLOAT);
367}
368
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000369bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
370{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000371 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372}
373
374bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
375{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000376 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377}
378
379bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
380{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000381 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000382}
383
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000384template<typename T>
385void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000386{
387 int copyWidth = std::min(targetWidth, srcWidth);
388 int copyHeight = std::min(targetHeight, srcHeight);
389
390 for (int x = 0; x < copyWidth; x++)
391 {
392 for (int y = 0; y < copyHeight; y++)
393 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000394 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000395 }
396 }
397 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000398 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000400 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000401 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000402 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000403 }
404 }
405 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000406 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000407 {
408 for (int x = 0; x < targetWidth; x++)
409 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000410 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000411 }
412 }
413}
414
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000415template<typename T>
416void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
417{
418 int copyWidth = std::min(targetWidth, srcWidth);
419 int copyHeight = std::min(targetHeight, srcHeight);
420
421 for (int y = 0; y < copyHeight; y++)
422 {
423 for (int x = 0; x < copyWidth; x++)
424 {
425 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
426 }
427 }
428 // clear unfilled right side
429 for (int y = 0; y < copyHeight; y++)
430 {
431 for (int x = copyWidth; x < targetWidth; x++)
432 {
433 target[y * targetWidth + x] = static_cast<T>(0);
434 }
435 }
436 // clear unfilled bottom.
437 for (int y = copyHeight; y < targetHeight; y++)
438 {
439 for (int x = 0; x < targetWidth; x++)
440 {
441 target[y * targetWidth + x] = static_cast<T>(0);
442 }
443 }
444}
445
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000446template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000447bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448{
449 if (location < 0 || location >= (int)mUniformIndex.size())
450 {
451 return false;
452 }
453
454 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
455 targetUniform->dirty = true;
456
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000457 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000458 {
459 return false;
460 }
461
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000462 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000463
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000464 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
466
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000467 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000468 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4 * rows);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000469
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000470 for (int i = 0; i < count; i++)
471 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000472 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
473 if (transpose == GL_FALSE)
474 {
475 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
476 }
477 else
478 {
479 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
480 }
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000481 target += 4 * rows;
482 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000483 }
484
485 return true;
486}
487
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000488bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000489{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000490 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000491}
492
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000493bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000494{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000495 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000496}
497
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000498bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000499{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000500 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501}
502
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000503bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000504{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000505 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000506}
507
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000508bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000509{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000510 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000511}
512
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000513bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000514{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000515 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000516}
517
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000518bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000519{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000520 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000521}
522
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000523bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000524{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000525 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000526}
527
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000528bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000529{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000530 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000531}
532
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000533bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
534{
535 if (location < 0 || location >= (int)mUniformIndex.size())
536 {
537 return false;
538 }
539
540 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
541 targetUniform->dirty = true;
542
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000543 int elementCount = targetUniform->elementCount();
544
545 if (elementCount == 1 && count > 1)
546 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
547
548 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
549
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000550 if (targetUniform->type == GL_INT ||
551 targetUniform->type == GL_SAMPLER_2D ||
552 targetUniform->type == GL_SAMPLER_CUBE)
553 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000554 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000556 for (int i = 0; i < count; i++)
557 {
558 target[0] = v[0];
559 target[1] = 0;
560 target[2] = 0;
561 target[3] = 0;
562 target += 4;
563 v += 1;
564 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000565 }
566 else if (targetUniform->type == GL_BOOL)
567 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000568 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000569
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000570 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000571 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000572 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
573 boolParams[1] = GL_FALSE;
574 boolParams[2] = GL_FALSE;
575 boolParams[3] = GL_FALSE;
576 boolParams += 4;
577 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578 }
579 }
580 else
581 {
582 return false;
583 }
584
585 return true;
586}
587
588bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
589{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000590 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000591}
592
593bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
594{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000595 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000596}
597
598bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
599{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000600 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000601}
602
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000603bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
604{
605 return setUniform(location, count, v, GL_UNSIGNED_INT);
606}
607
608bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
609{
610 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
611}
612
613bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
614{
615 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
616}
617
618bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
619{
620 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
621}
622
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000623template <typename T>
624bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000625{
626 if (location < 0 || location >= (int)mUniformIndex.size())
627 {
628 return false;
629 }
630
631 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
632
633 // sized queries -- ensure the provided buffer is large enough
634 if (bufSize)
635 {
636 int requiredBytes = UniformExternalSize(targetUniform->type);
637 if (*bufSize < requiredBytes)
638 {
639 return false;
640 }
641 }
642
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000643 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000644 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000645 const int rows = VariableRowCount(targetUniform->type);
646 const int cols = VariableColumnCount(targetUniform->type);
647 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
648 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000649 else if (uniformType == UniformComponentType(targetUniform->type))
650 {
651 unsigned int size = UniformComponentCount(targetUniform->type);
652 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
653 size * sizeof(T));
654 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000655 else
656 {
657 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000658 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000659 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000660 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000661 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000662 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000663
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000664 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000666 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000669 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000670
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000671 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000672 {
673 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
674
675 for (unsigned int i = 0; i < size; i++)
676 {
677 params[i] = static_cast<T>(floatParams[i]);
678 }
679 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000680 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000681
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000682 case GL_INT:
683 {
684 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
685
686 for (unsigned int i = 0; i < size; i++)
687 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000688 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000689 }
690 }
691 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000692
693 case GL_UNSIGNED_INT:
694 {
695 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000696
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000697 for (unsigned int i = 0; i < size; i++)
698 {
699 params[i] = static_cast<T>(uintParams[i]);
700 }
701 }
702 break;
703
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000704 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000705 }
706 }
707
708 return true;
709}
710
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000711bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
712{
713 return getUniformv(location, bufSize, params, GL_FLOAT);
714}
715
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000716bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
717{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000718 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000719}
720
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000721bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
722{
723 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
724}
725
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726void ProgramBinary::dirtyAllUniforms()
727{
728 unsigned int numUniforms = mUniforms.size();
729 for (unsigned int index = 0; index < numUniforms; index++)
730 {
731 mUniforms[index]->dirty = true;
732 }
733}
734
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000735// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000736void ProgramBinary::applyUniforms()
737{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000738 // Retrieve sampler uniform values
739 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
740 {
741 Uniform *targetUniform = *ub;
742
743 if (targetUniform->dirty)
744 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000745 if (targetUniform->type == GL_SAMPLER_2D ||
746 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000747 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000748 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000749 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000750
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000751 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000752 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000753 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000754
755 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000756 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000757 unsigned int samplerIndex = firstIndex + i;
758
759 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000760 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000761 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000762 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000763 }
764 }
765 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000766
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000767 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000768 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000769 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000770
771 for (int i = 0; i < count; i++)
772 {
773 unsigned int samplerIndex = firstIndex + i;
774
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000775 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000776 {
777 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000778 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000779 }
780 }
781 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000782 }
783 }
784 }
785
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000786 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000787}
788
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
790// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000791int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000792{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000793 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000794
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000795 fragmentShader->resetVaryingsRegisterAssignment();
796
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000797 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
798 {
799 int n = VariableRowCount(varying->type) * varying->size;
800 int m = VariableColumnCount(varying->type);
801 bool success = false;
802
803 if (m == 2 || m == 3 || m == 4)
804 {
805 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
806 {
807 bool available = true;
808
809 for (int y = 0; y < n && available; y++)
810 {
811 for (int x = 0; x < m && available; x++)
812 {
813 if (packing[r + y][x])
814 {
815 available = false;
816 }
817 }
818 }
819
820 if (available)
821 {
822 varying->reg = r;
823 varying->col = 0;
824
825 for (int y = 0; y < n; y++)
826 {
827 for (int x = 0; x < m; x++)
828 {
829 packing[r + y][x] = &*varying;
830 }
831 }
832
833 success = true;
834 }
835 }
836
837 if (!success && m == 2)
838 {
839 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
840 {
841 bool available = true;
842
843 for (int y = 0; y < n && available; y++)
844 {
845 for (int x = 2; x < 4 && available; x++)
846 {
847 if (packing[r + y][x])
848 {
849 available = false;
850 }
851 }
852 }
853
854 if (available)
855 {
856 varying->reg = r;
857 varying->col = 2;
858
859 for (int y = 0; y < n; y++)
860 {
861 for (int x = 2; x < 4; x++)
862 {
863 packing[r + y][x] = &*varying;
864 }
865 }
866
867 success = true;
868 }
869 }
870 }
871 }
872 else if (m == 1)
873 {
874 int space[4] = {0};
875
876 for (int y = 0; y < maxVaryingVectors; y++)
877 {
878 for (int x = 0; x < 4; x++)
879 {
880 space[x] += packing[y][x] ? 0 : 1;
881 }
882 }
883
884 int column = 0;
885
886 for (int x = 0; x < 4; x++)
887 {
888 if (space[x] >= n && space[x] < space[column])
889 {
890 column = x;
891 }
892 }
893
894 if (space[column] >= n)
895 {
896 for (int r = 0; r < maxVaryingVectors; r++)
897 {
898 if (!packing[r][column])
899 {
900 varying->reg = r;
901
902 for (int y = r; y < r + n; y++)
903 {
904 packing[y][column] = &*varying;
905 }
906
907 break;
908 }
909 }
910
911 varying->col = column;
912
913 success = true;
914 }
915 }
916 else UNREACHABLE();
917
918 if (!success)
919 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000920 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000921
922 return -1;
923 }
924 }
925
926 // Return the number of used registers
927 int registers = 0;
928
929 for (int r = 0; r < maxVaryingVectors; r++)
930 {
931 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
932 {
933 registers++;
934 }
935 }
936
937 return registers;
938}
939
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000940bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
941 std::string& pixelHLSL, std::string& vertexHLSL,
942 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000943{
944 if (pixelHLSL.empty() || vertexHLSL.empty())
945 {
946 return false;
947 }
948
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000949 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
950 bool usesFragColor = fragmentShader->mUsesFragColor;
951 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +0000952 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000953 {
954 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
955 return false;
956 }
957
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000958 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +0000959 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000960 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000961
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000962 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
963
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +0000964 // Two cases when writing to gl_FragColor and using ESSL 1.0:
965 // - with a 3.0 context, the output color is copied to channel 0
966 // - with a 2.0 context, the output color is broadcast to all channels
967 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
968 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
969
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000970 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000971 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000972 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000973
974 return false;
975 }
976
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000977 vertexShader->resetVaryingsRegisterAssignment();
978
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000979 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
980 {
981 bool matched = false;
982
983 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
984 {
985 if (output->name == input->name)
986 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000987 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000988 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000989 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 +0000990
991 return false;
992 }
993
994 output->reg = input->reg;
995 output->col = input->col;
996
997 matched = true;
998 break;
999 }
1000 }
1001
1002 if (!matched)
1003 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001004 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001005
1006 return false;
1007 }
1008 }
1009
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001010 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001011 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001012 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001013 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1014
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001015 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1016
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001017 // special varyings that use reserved registers
1018 int reservedRegisterIndex = registers;
1019 std::string fragCoordSemantic;
1020 std::string pointCoordSemantic;
1021
1022 if (fragmentShader->mUsesFragCoord)
1023 {
1024 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1025 }
1026
1027 if (fragmentShader->mUsesPointCoord)
1028 {
1029 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1030 // In DX11 we compute this in the GS.
1031 if (shaderModel == 3)
1032 {
1033 pointCoordSemantic = "TEXCOORD0";
1034 }
1035 else if (shaderModel >= 4)
1036 {
1037 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1038 }
1039 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001040
1041 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001042 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001043
1044 int semanticIndex = 0;
1045 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1046 {
1047 switch (attribute->type)
1048 {
1049 case GL_FLOAT: vertexHLSL += " float "; break;
1050 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1051 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1052 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1053 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1054 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1055 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1056 default: UNREACHABLE();
1057 }
1058
1059 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1060
1061 semanticIndex += VariableRowCount(attribute->type);
1062 }
1063
1064 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001065 "\n"
1066 "struct VS_OUTPUT\n"
1067 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001068
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001069 if (shaderModel < 4)
1070 {
1071 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1072 }
1073
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001074 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001075
1076 if (fragmentShader->mUsesFragCoord)
1077 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001078 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001079 }
1080
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001081 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001082 {
1083 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1084 }
1085
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001086 if (shaderModel >= 4)
1087 {
1088 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1089 }
1090
1091 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001092 "\n"
1093 "VS_OUTPUT main(VS_INPUT input)\n"
1094 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001095
1096 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1097 {
1098 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1099
1100 if (VariableRowCount(attribute->type) > 1) // Matrix
1101 {
1102 vertexHLSL += "transpose";
1103 }
1104
1105 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1106 }
1107
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001108 if (shaderModel >= 4)
1109 {
1110 vertexHLSL += "\n"
1111 " gl_main();\n"
1112 "\n"
1113 " VS_OUTPUT output;\n"
1114 " output.gl_Position.x = gl_Position.x;\n"
1115 " output.gl_Position.y = -gl_Position.y;\n"
1116 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1117 " output.gl_Position.w = gl_Position.w;\n";
1118 }
1119 else
1120 {
1121 vertexHLSL += "\n"
1122 " gl_main();\n"
1123 "\n"
1124 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001125 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1126 " 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 +00001127 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1128 " output.gl_Position.w = gl_Position.w;\n";
1129 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001130
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001131 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001132 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001133 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001134 }
1135
1136 if (fragmentShader->mUsesFragCoord)
1137 {
1138 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1139 }
1140
1141 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1142 {
1143 if (varying->reg >= 0)
1144 {
1145 for (int i = 0; i < varying->size; i++)
1146 {
1147 int rows = VariableRowCount(varying->type);
1148
1149 for (int j = 0; j < rows; j++)
1150 {
1151 int r = varying->reg + i * rows + j;
1152 vertexHLSL += " output.v" + str(r);
1153
1154 bool sharedRegister = false; // Register used by multiple varyings
1155
1156 for (int x = 0; x < 4; x++)
1157 {
1158 if (packing[r][x] && packing[r][x] != packing[r][0])
1159 {
1160 sharedRegister = true;
1161 break;
1162 }
1163 }
1164
1165 if(sharedRegister)
1166 {
1167 vertexHLSL += ".";
1168
1169 for (int x = 0; x < 4; x++)
1170 {
1171 if (packing[r][x] == &*varying)
1172 {
1173 switch(x)
1174 {
1175 case 0: vertexHLSL += "x"; break;
1176 case 1: vertexHLSL += "y"; break;
1177 case 2: vertexHLSL += "z"; break;
1178 case 3: vertexHLSL += "w"; break;
1179 }
1180 }
1181 }
1182 }
1183
1184 vertexHLSL += " = " + varying->name;
1185
1186 if (varying->array)
1187 {
1188 vertexHLSL += "[" + str(i) + "]";
1189 }
1190
1191 if (rows > 1)
1192 {
1193 vertexHLSL += "[" + str(j) + "]";
1194 }
1195
1196 vertexHLSL += ";\n";
1197 }
1198 }
1199 }
1200 }
1201
1202 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001203 " return output;\n"
1204 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001205
1206 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001207 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001209 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001210
1211 if (fragmentShader->mUsesFragCoord)
1212 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001213 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001214 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001215
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001216 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1217 {
1218 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1219 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001220
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001221 // Must consume the PSIZE element if the geometry shader is not active
1222 // We won't know if we use a GS until we draw
1223 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1224 {
1225 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1226 }
1227
1228 if (fragmentShader->mUsesFragCoord)
1229 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001230 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001231 {
1232 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1233 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001234 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001235 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001236 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1237 }
1238 }
1239
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001240 pixelHLSL += "};\n"
1241 "\n"
1242 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001243 "{\n";
1244
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001245 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001246 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001247 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001248 }
1249
1250 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001251 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001252
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001253 if (fragmentShader->mUsesFrontFacing)
1254 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001255 if (shaderModel >= 4)
1256 {
1257 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1258 "{\n";
1259 }
1260 else
1261 {
1262 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1263 "{\n";
1264 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001265 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001266 else
1267 {
1268 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1269 "{\n";
1270 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001271
1272 if (fragmentShader->mUsesFragCoord)
1273 {
1274 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1275
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001276 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001277 {
1278 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1279 " gl_FragCoord.y = input.dx_VPos.y;\n";
1280 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001281 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001282 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001283 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001284 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001285 }
1286 else
1287 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001288 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1289 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1290 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001291 }
1292
daniel@transgaming.com12985182012-12-20 20:56:31 +00001293 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001294 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295 }
1296
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001297 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001299 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1300 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001301 }
1302
1303 if (fragmentShader->mUsesFrontFacing)
1304 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001305 if (shaderModel <= 3)
1306 {
1307 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1308 }
1309 else
1310 {
1311 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1312 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001313 }
1314
1315 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1316 {
1317 if (varying->reg >= 0)
1318 {
1319 for (int i = 0; i < varying->size; i++)
1320 {
1321 int rows = VariableRowCount(varying->type);
1322 for (int j = 0; j < rows; j++)
1323 {
1324 std::string n = str(varying->reg + i * rows + j);
1325 pixelHLSL += " " + varying->name;
1326
1327 if (varying->array)
1328 {
1329 pixelHLSL += "[" + str(i) + "]";
1330 }
1331
1332 if (rows > 1)
1333 {
1334 pixelHLSL += "[" + str(j) + "]";
1335 }
1336
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001337 switch (VariableColumnCount(varying->type))
1338 {
1339 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1340 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1341 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1342 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1343 default: UNREACHABLE();
1344 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001345 }
1346 }
1347 }
1348 else UNREACHABLE();
1349 }
1350
1351 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001352 " gl_main();\n"
1353 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001354 " PS_OUTPUT output;\n";
1355
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001356 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001357 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001358 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001359
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001360 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001361 }
1362
1363 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001364 " return output;\n"
1365 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001366
1367 return true;
1368}
1369
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001370std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1371{
1372 std::string varyingHLSL;
1373
1374 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1375 {
1376 if (varying->reg >= 0)
1377 {
1378 for (int i = 0; i < varying->size; i++)
1379 {
1380 int rows = VariableRowCount(varying->type);
1381 for (int j = 0; j < rows; j++)
1382 {
1383 switch (varying->interpolation)
1384 {
1385 case Smooth: varyingHLSL += " "; break;
1386 case Flat: varyingHLSL += " nointerpolation "; break;
1387 case Centroid: varyingHLSL += " centroid "; break;
1388 default: UNREACHABLE();
1389 }
1390
1391 std::string n = str(varying->reg + i * rows + j);
1392 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1393 }
1394 }
1395 }
1396 else UNREACHABLE();
1397 }
1398
1399 return varyingHLSL;
1400}
1401
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001402bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1403{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001404 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001405
1406 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001407 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001408 if (format != GL_PROGRAM_BINARY_ANGLE)
1409 {
1410 infoLog.append("Invalid program binary format.");
1411 return false;
1412 }
1413
1414 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001415 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001416 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001417 {
1418 infoLog.append("Invalid program binary version.");
1419 return false;
1420 }
1421
1422 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1423 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001424 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001425 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001426 stream.read(&name);
1427 mLinkedAttribute[i].name = name;
1428 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001429 }
1430
1431 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1432 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001433 stream.read(&mSamplersPS[i].active);
1434 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001435
1436 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001437 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001438 mSamplersPS[i].textureType = (TextureType) textureType;
1439 }
1440
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001441 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001442 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001443 stream.read(&mSamplersVS[i].active);
1444 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001445
1446 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001447 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001448 mSamplersVS[i].textureType = (TextureType) textureType;
1449 }
1450
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001451 stream.read(&mUsedVertexSamplerRange);
1452 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001453 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001454
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001455 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001456 stream.read(&size);
1457 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001458 {
1459 infoLog.append("Invalid program binary.");
1460 return false;
1461 }
1462
1463 mUniforms.resize(size);
1464 for (unsigned int i = 0; i < size; ++i)
1465 {
1466 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001467 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001468 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001469 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001470 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001471
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001472 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001473 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001474 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001475 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001476 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001477
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001478 int offset;
1479 int arrayStride;
1480 int matrixStride;
1481 bool isRowMajorMatrix;
1482
1483 stream.read(&offset);
1484 stream.read(&arrayStride);
1485 stream.read(&matrixStride);
1486 stream.read(&isRowMajorMatrix);
1487
1488 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1489
1490 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001491
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001492 stream.read(&mUniforms[i]->psRegisterIndex);
1493 stream.read(&mUniforms[i]->vsRegisterIndex);
1494 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001495 }
1496
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001497 stream.read(&size);
1498 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001499 {
1500 infoLog.append("Invalid program binary.");
1501 return false;
1502 }
1503
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001504 mUniformBlocks.resize(size);
1505 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1506 {
1507 std::string name;
1508 unsigned int elementIndex;
1509 unsigned int dataSize;
1510
1511 stream.read(&name);
1512 stream.read(&elementIndex);
1513 stream.read(&dataSize);
1514
1515 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1516
1517 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1518 stream.read(&uniformBlock.psRegisterIndex);
1519 stream.read(&uniformBlock.vsRegisterIndex);
1520
1521 size_t numMembers;
1522 stream.read(&numMembers);
1523 uniformBlock.memberUniformIndexes.resize(numMembers);
1524 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1525 {
1526 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1527 }
1528 }
1529
1530 stream.read(&size);
1531 if (stream.error())
1532 {
1533 infoLog.append("Invalid program binary.");
1534 return false;
1535 }
1536
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001537 mUniformIndex.resize(size);
1538 for (unsigned int i = 0; i < size; ++i)
1539 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001540 stream.read(&mUniformIndex[i].name);
1541 stream.read(&mUniformIndex[i].element);
1542 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001543 }
1544
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001545 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001546 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001547
1548 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001549 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001550
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001551 unsigned int geometryShaderSize;
1552 stream.read(&geometryShaderSize);
1553
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001554 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555
daniel@transgaming.com36038542012-11-28 20:59:26 +00001556 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001557 ptr += sizeof(GUID);
1558
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001559 GUID identifier = mRenderer->getAdapterIdentifier();
1560 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561 {
1562 infoLog.append("Invalid program binary.");
1563 return false;
1564 }
1565
1566 const char *pixelShaderFunction = ptr;
1567 ptr += pixelShaderSize;
1568
1569 const char *vertexShaderFunction = ptr;
1570 ptr += vertexShaderSize;
1571
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001572 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1573 ptr += geometryShaderSize;
1574
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001575 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001576 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001577 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578 {
1579 infoLog.append("Could not create pixel shader.");
1580 return false;
1581 }
1582
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001583 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001584 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001585 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001586 {
1587 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001588 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001589 mPixelExecutable = NULL;
1590 return false;
1591 }
1592
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001593 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1594 {
1595 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1596 geometryShaderSize, rx::SHADER_GEOMETRY);
1597 if (!mGeometryExecutable)
1598 {
1599 infoLog.append("Could not create geometry shader.");
1600 delete mPixelExecutable;
1601 mPixelExecutable = NULL;
1602 delete mVertexExecutable;
1603 mVertexExecutable = NULL;
1604 return false;
1605 }
1606 }
1607 else
1608 {
1609 mGeometryExecutable = NULL;
1610 }
1611
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001612 return true;
1613}
1614
1615bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1616{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001617 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001619 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001620 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621
1622 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1623 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.write(mLinkedAttribute[i].type);
1625 stream.write(mLinkedAttribute[i].name);
1626 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 }
1628
1629 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1630 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.write(mSamplersPS[i].active);
1632 stream.write(mSamplersPS[i].logicalTextureUnit);
1633 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 }
1635
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001636 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001637 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001638 stream.write(mSamplersVS[i].active);
1639 stream.write(mSamplersVS[i].logicalTextureUnit);
1640 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641 }
1642
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001643 stream.write(mUsedVertexSamplerRange);
1644 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001645 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001648 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001650 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001652 stream.write(uniform.type);
1653 stream.write(uniform.precision);
1654 stream.write(uniform.name);
1655 stream.write(uniform.arraySize);
1656 stream.write(uniform.blockIndex);
1657
1658 stream.write(uniform.blockInfo.offset);
1659 stream.write(uniform.blockInfo.arrayStride);
1660 stream.write(uniform.blockInfo.matrixStride);
1661 stream.write(uniform.blockInfo.isRowMajorMatrix);
1662
1663 stream.write(uniform.psRegisterIndex);
1664 stream.write(uniform.vsRegisterIndex);
1665 stream.write(uniform.registerCount);
1666 }
1667
1668 stream.write(mUniformBlocks.size());
1669 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1670 {
1671 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1672
1673 stream.write(uniformBlock.name);
1674 stream.write(uniformBlock.elementIndex);
1675 stream.write(uniformBlock.dataSize);
1676
1677 stream.write(uniformBlock.memberUniformIndexes.size());
1678 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1679 {
1680 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1681 }
1682
1683 stream.write(uniformBlock.psRegisterIndex);
1684 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001685 }
1686
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001687 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1689 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001690 stream.write(mUniformIndex[i].name);
1691 stream.write(mUniformIndex[i].element);
1692 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693 }
1694
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001695 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001696 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001698 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001699 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001700
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001701 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1702 stream.write(geometryShaderSize);
1703
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001704 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 GLsizei streamLength = stream.length();
1707 const void *streamData = stream.data();
1708
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001709 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710 if (totalLength > bufSize)
1711 {
1712 if (length)
1713 {
1714 *length = 0;
1715 }
1716
1717 return false;
1718 }
1719
1720 if (binary)
1721 {
1722 char *ptr = (char*) binary;
1723
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001724 memcpy(ptr, streamData, streamLength);
1725 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001726
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001727 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001728 ptr += sizeof(GUID);
1729
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001730 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001731 ptr += pixelShaderSize;
1732
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001733 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001734 ptr += vertexShaderSize;
1735
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001736 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1737 {
1738 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1739 ptr += geometryShaderSize;
1740 }
1741
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001742 ASSERT(ptr - totalLength == binary);
1743 }
1744
1745 if (length)
1746 {
1747 *length = totalLength;
1748 }
1749
1750 return true;
1751}
1752
1753GLint ProgramBinary::getLength()
1754{
1755 GLint length;
1756 if (save(NULL, INT_MAX, &length))
1757 {
1758 return length;
1759 }
1760 else
1761 {
1762 return 0;
1763 }
1764}
1765
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001766bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001767{
1768 if (!fragmentShader || !fragmentShader->isCompiled())
1769 {
1770 return false;
1771 }
1772
1773 if (!vertexShader || !vertexShader->isCompiled())
1774 {
1775 return false;
1776 }
1777
1778 std::string pixelHLSL = fragmentShader->getHLSL();
1779 std::string vertexHLSL = vertexShader->getHLSL();
1780
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001781 // Map the varyings to the register file
1782 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1783 int registers = packVaryings(infoLog, packing, fragmentShader);
1784
1785 if (registers < 0)
1786 {
1787 return false;
1788 }
1789
1790 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001791 {
1792 return false;
1793 }
1794
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001795 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001796 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1797 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001798
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001799 if (usesGeometryShader())
1800 {
1801 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1802 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1803 }
1804
1805 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001806 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001807 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001808 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001809
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001810 delete mVertexExecutable;
1811 mVertexExecutable = NULL;
1812 delete mPixelExecutable;
1813 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001814 delete mGeometryExecutable;
1815 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001816 }
1817
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001818 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1819 {
1820 success = false;
1821 }
1822
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001823 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001824 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001825 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001826 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001827
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001828 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1829 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1830 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001831 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1832 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1833 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 +00001834 }
1835
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001836 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001837}
1838
1839// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001840bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001841{
1842 unsigned int usedLocations = 0;
1843
1844 // Link attributes that have a binding location
1845 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1846 {
1847 int location = attributeBindings.getAttributeBinding(attribute->name);
1848
1849 if (location != -1) // Set by glBindAttribLocation
1850 {
1851 if (!mLinkedAttribute[location].name.empty())
1852 {
1853 // Multiple active attributes bound to the same location; not an error
1854 }
1855
1856 mLinkedAttribute[location] = *attribute;
1857
1858 int rows = VariableRowCount(attribute->type);
1859
1860 if (rows + location > MAX_VERTEX_ATTRIBS)
1861 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001862 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 +00001863
1864 return false;
1865 }
1866
1867 for (int i = 0; i < rows; i++)
1868 {
1869 usedLocations |= 1 << (location + i);
1870 }
1871 }
1872 }
1873
1874 // Link attributes that don't have a binding location
1875 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1876 {
1877 int location = attributeBindings.getAttributeBinding(attribute->name);
1878
1879 if (location == -1) // Not set by glBindAttribLocation
1880 {
1881 int rows = VariableRowCount(attribute->type);
1882 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1883
1884 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1885 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001886 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001887
1888 return false; // Fail to link
1889 }
1890
1891 mLinkedAttribute[availableIndex] = *attribute;
1892 }
1893 }
1894
1895 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1896 {
1897 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1898 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1899
1900 for (int r = 0; r < rows; r++)
1901 {
1902 mSemanticIndex[attributeIndex++] = index++;
1903 }
1904 }
1905
1906 return true;
1907}
1908
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001909bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001910{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001911 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001912 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001913 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001914 {
1915 return false;
1916 }
1917 }
1918
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001919 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001920 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001921 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001922 {
1923 return false;
1924 }
1925 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001926
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001927 return true;
1928}
1929
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001930bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001931{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001932 if (constant.type == GL_SAMPLER_2D ||
1933 constant.type == GL_SAMPLER_CUBE)
1934 {
1935 unsigned int samplerIndex = constant.registerIndex;
1936
1937 do
1938 {
1939 if (shader == GL_VERTEX_SHADER)
1940 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001941 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001942 {
1943 mSamplersVS[samplerIndex].active = true;
1944 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1945 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1946 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1947 }
1948 else
1949 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001950 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001951 return false;
1952 }
1953 }
1954 else if (shader == GL_FRAGMENT_SHADER)
1955 {
1956 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1957 {
1958 mSamplersPS[samplerIndex].active = true;
1959 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1960 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1961 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1962 }
1963 else
1964 {
1965 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1966 return false;
1967 }
1968 }
1969 else UNREACHABLE();
1970
1971 samplerIndex++;
1972 }
1973 while (samplerIndex < constant.registerIndex + constant.arraySize);
1974 }
1975
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001976 Uniform *uniform = NULL;
1977 GLint location = getUniformLocation(constant.name);
1978
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001979 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001980 {
1981 uniform = mUniforms[mUniformIndex[location].index];
1982
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001983 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001984 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001985 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1986 return false;
1987 }
1988
1989 if (uniform->precision != constant.precision)
1990 {
1991 infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001992 return false;
1993 }
1994 }
1995 else
1996 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001997 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001998 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001999
2000 if (!uniform)
2001 {
2002 return false;
2003 }
2004
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002005 if (shader == GL_FRAGMENT_SHADER)
2006 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002007 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002008 }
2009 else if (shader == GL_VERTEX_SHADER)
2010 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002011 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002012 }
2013 else UNREACHABLE();
2014
2015 if (location >= 0)
2016 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002017 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002018 }
2019
2020 mUniforms.push_back(uniform);
2021 unsigned int uniformIndex = mUniforms.size() - 1;
2022
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002023 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002024 {
2025 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2026 }
2027
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002028 if (shader == GL_VERTEX_SHADER)
2029 {
2030 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2031 {
2032 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2033 return false;
2034 }
2035 }
2036 else if (shader == GL_FRAGMENT_SHADER)
2037 {
2038 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2039 {
2040 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2041 return false;
2042 }
2043 }
2044 else UNREACHABLE();
2045
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002046 return true;
2047}
2048
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002049std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2050{
2051 // for now we only handle point sprite emulation
2052 ASSERT(usesPointSpriteEmulation());
2053 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2054}
2055
2056std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2057{
2058 ASSERT(registers >= 0);
2059 ASSERT(vertexShader->mUsesPointSize);
2060 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2061
2062 std::string geomHLSL;
2063
2064 std::string varyingSemantic = "TEXCOORD";
2065
2066 std::string fragCoordSemantic;
2067 std::string pointCoordSemantic;
2068
2069 int reservedRegisterIndex = registers;
2070
2071 if (fragmentShader->mUsesFragCoord)
2072 {
2073 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2074 }
2075
2076 if (fragmentShader->mUsesPointCoord)
2077 {
2078 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2079 }
2080
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002081 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2082 "\n"
2083 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002084 "{\n";
2085
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002086 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002087
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002088 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002089
2090 if (fragmentShader->mUsesFragCoord)
2091 {
2092 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2093 }
2094
2095 geomHLSL += " float gl_PointSize : PSIZE;\n"
2096 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002097 "};\n"
2098 "\n"
2099 "struct GS_OUTPUT\n"
2100 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002101
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002102 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002103
2104 if (fragmentShader->mUsesFragCoord)
2105 {
2106 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2107 }
2108
2109 if (fragmentShader->mUsesPointCoord)
2110 {
2111 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2112 }
2113
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002114 geomHLSL += " float gl_PointSize : PSIZE;\n"
2115 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002116 "};\n"
2117 "\n"
2118 "static float2 pointSpriteCorners[] = \n"
2119 "{\n"
2120 " float2( 0.5f, -0.5f),\n"
2121 " float2( 0.5f, 0.5f),\n"
2122 " float2(-0.5f, -0.5f),\n"
2123 " float2(-0.5f, 0.5f)\n"
2124 "};\n"
2125 "\n"
2126 "static float2 pointSpriteTexcoords[] = \n"
2127 "{\n"
2128 " float2(1.0f, 1.0f),\n"
2129 " float2(1.0f, 0.0f),\n"
2130 " float2(0.0f, 1.0f),\n"
2131 " float2(0.0f, 0.0f)\n"
2132 "};\n"
2133 "\n"
2134 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2135 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2136 "\n"
2137 "[maxvertexcount(4)]\n"
2138 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2139 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002140 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2141 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002142
2143 for (int r = 0; r < registers; r++)
2144 {
2145 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2146 }
2147
2148 if (fragmentShader->mUsesFragCoord)
2149 {
2150 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2151 }
2152
2153 geomHLSL += " \n"
2154 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2155 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002156 " 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 +00002157
2158 for (int corner = 0; corner < 4; corner++)
2159 {
2160 geomHLSL += " \n"
2161 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2162
2163 if (fragmentShader->mUsesPointCoord)
2164 {
2165 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2166 }
2167
2168 geomHLSL += " outStream.Append(output);\n";
2169 }
2170
2171 geomHLSL += " \n"
2172 " outStream.RestartStrip();\n"
2173 "}\n";
2174
2175 return geomHLSL;
2176}
2177
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002178// This method needs to match OutputHLSL::decorate
2179std::string ProgramBinary::decorateAttribute(const std::string &name)
2180{
2181 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2182 {
2183 return "_" + name;
2184 }
2185
2186 return name;
2187}
2188
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002189bool ProgramBinary::isValidated() const
2190{
2191 return mValidated;
2192}
2193
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002194void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002195{
2196 // Skip over inactive attributes
2197 unsigned int activeAttribute = 0;
2198 unsigned int attribute;
2199 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2200 {
2201 if (mLinkedAttribute[attribute].name.empty())
2202 {
2203 continue;
2204 }
2205
2206 if (activeAttribute == index)
2207 {
2208 break;
2209 }
2210
2211 activeAttribute++;
2212 }
2213
2214 if (bufsize > 0)
2215 {
2216 const char *string = mLinkedAttribute[attribute].name.c_str();
2217
2218 strncpy(name, string, bufsize);
2219 name[bufsize - 1] = '\0';
2220
2221 if (length)
2222 {
2223 *length = strlen(name);
2224 }
2225 }
2226
2227 *size = 1; // Always a single 'type' instance
2228
2229 *type = mLinkedAttribute[attribute].type;
2230}
2231
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002232GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002233{
2234 int count = 0;
2235
2236 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2237 {
2238 if (!mLinkedAttribute[attributeIndex].name.empty())
2239 {
2240 count++;
2241 }
2242 }
2243
2244 return count;
2245}
2246
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002247GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002248{
2249 int maxLength = 0;
2250
2251 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2252 {
2253 if (!mLinkedAttribute[attributeIndex].name.empty())
2254 {
2255 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2256 }
2257 }
2258
2259 return maxLength;
2260}
2261
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002262void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002263{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002264 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002265
2266 if (bufsize > 0)
2267 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002268 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002269
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002270 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002271 {
2272 string += "[0]";
2273 }
2274
2275 strncpy(name, string.c_str(), bufsize);
2276 name[bufsize - 1] = '\0';
2277
2278 if (length)
2279 {
2280 *length = strlen(name);
2281 }
2282 }
2283
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002284 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002285
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002286 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002287}
2288
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002289GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002290{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002291 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002292}
2293
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002294GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002295{
2296 int maxLength = 0;
2297
2298 unsigned int numUniforms = mUniforms.size();
2299 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2300 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002301 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002302 {
2303 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2304 if (mUniforms[uniformIndex]->isArray())
2305 {
2306 length += 3; // Counting in "[0]".
2307 }
2308 maxLength = std::max(length, maxLength);
2309 }
2310 }
2311
2312 return maxLength;
2313}
2314
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002315GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2316{
2317 const gl::Uniform& uniform = *mUniforms[index];
2318
2319 switch (pname)
2320 {
2321 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2322 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2323 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002324 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002325
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002326 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2327 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2328 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2329 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002330
2331 default:
2332 UNREACHABLE();
2333 break;
2334 }
2335 return 0;
2336}
2337
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002338void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002339{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002340 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002341 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002342 {
2343 mValidated = false;
2344 }
2345 else
2346 {
2347 mValidated = true;
2348 }
2349}
2350
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002351bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002352{
2353 // if any two active samplers in a program are of different types, but refer to the same
2354 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2355 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2356
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002357 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002358 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002359
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002360 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002361 {
2362 textureUnitType[i] = TEXTURE_UNKNOWN;
2363 }
2364
2365 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2366 {
2367 if (mSamplersPS[i].active)
2368 {
2369 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2370
2371 if (unit >= maxCombinedTextureImageUnits)
2372 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002373 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002374 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002375 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002376 }
2377
2378 return false;
2379 }
2380
2381 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2382 {
2383 if (mSamplersPS[i].textureType != textureUnitType[unit])
2384 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002385 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002386 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002387 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388 }
2389
2390 return false;
2391 }
2392 }
2393 else
2394 {
2395 textureUnitType[unit] = mSamplersPS[i].textureType;
2396 }
2397 }
2398 }
2399
2400 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2401 {
2402 if (mSamplersVS[i].active)
2403 {
2404 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2405
2406 if (unit >= maxCombinedTextureImageUnits)
2407 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002408 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002409 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002410 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002411 }
2412
2413 return false;
2414 }
2415
2416 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2417 {
2418 if (mSamplersVS[i].textureType != textureUnitType[unit])
2419 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002420 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002421 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002422 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002423 }
2424
2425 return false;
2426 }
2427 }
2428 else
2429 {
2430 textureUnitType[unit] = mSamplersVS[i].textureType;
2431 }
2432 }
2433 }
2434
2435 return true;
2436}
2437
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002438ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2439{
2440}
2441
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002442struct AttributeSorter
2443{
2444 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2445 : originalIndices(semanticIndices)
2446 {
2447 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2448 {
2449 indices[i] = i;
2450 }
2451
2452 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2453 }
2454
2455 bool operator()(int a, int b)
2456 {
2457 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2458 }
2459
2460 int indices[MAX_VERTEX_ATTRIBS];
2461 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2462};
2463
2464void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2465{
2466 AttributeSorter sorter(mSemanticIndex);
2467
2468 int oldIndices[MAX_VERTEX_ATTRIBS];
2469 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2470
2471 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2472 {
2473 oldIndices[i] = mSemanticIndex[i];
2474 oldTranslatedAttributes[i] = attributes[i];
2475 }
2476
2477 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2478 {
2479 int oldIndex = sorter.indices[i];
2480 sortedSemanticIndices[i] = oldIndices[oldIndex];
2481 attributes[i] = oldTranslatedAttributes[oldIndex];
2482 }
2483}
2484
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002485}