blob: 9f51a9f82f70ef21dd83035f09bbae6eef5c2dd8 [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
daniel@transgaming.comdb019952012-12-20 21:13:32 +000038UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
39 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000040{
41}
42
daniel@transgaming.come87ca002012-07-24 18:30:43 +000043unsigned int ProgramBinary::mCurrentSerial = 1;
44
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000045ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000047 mPixelExecutable = NULL;
48 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000049 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000050
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000051 mValidated = false;
52
53 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
54 {
55 mSemanticIndex[index] = -1;
56 }
57
58 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
59 {
60 mSamplersPS[index].active = false;
61 }
62
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000063 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000064 {
65 mSamplersVS[index].active = false;
66 }
67
68 mUsedVertexSamplerRange = 0;
69 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000070 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071}
72
73ProgramBinary::~ProgramBinary()
74{
daniel@transgaming.com95892412012-11-28 20:59:09 +000075 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000076 mPixelExecutable = NULL;
77
daniel@transgaming.com95892412012-11-28 20:59:09 +000078 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000079 mVertexExecutable = NULL;
80
81 delete mGeometryExecutable;
82 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000084 while (!mUniforms.empty())
85 {
86 delete mUniforms.back();
87 mUniforms.pop_back();
88 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000089}
90
daniel@transgaming.come87ca002012-07-24 18:30:43 +000091unsigned int ProgramBinary::getSerial() const
92{
93 return mSerial;
94}
95
96unsigned int ProgramBinary::issueSerial()
97{
98 return mCurrentSerial++;
99}
100
daniel@transgaming.com95892412012-11-28 20:59:09 +0000101rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102{
103 return mPixelExecutable;
104}
105
daniel@transgaming.com95892412012-11-28 20:59:09 +0000106rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000107{
108 return mVertexExecutable;
109}
110
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000111rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
112{
113 return mGeometryExecutable;
114}
115
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116GLuint ProgramBinary::getAttributeLocation(const char *name)
117{
118 if (name)
119 {
120 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
121 {
122 if (mLinkedAttribute[index].name == std::string(name))
123 {
124 return index;
125 }
126 }
127 }
128
129 return -1;
130}
131
132int ProgramBinary::getSemanticIndex(int attributeIndex)
133{
134 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
135
136 return mSemanticIndex[attributeIndex];
137}
138
139// Returns one more than the highest sampler index used.
140GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
141{
142 switch (type)
143 {
144 case SAMPLER_PIXEL:
145 return mUsedPixelSamplerRange;
146 case SAMPLER_VERTEX:
147 return mUsedVertexSamplerRange;
148 default:
149 UNREACHABLE();
150 return 0;
151 }
152}
153
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000154bool ProgramBinary::usesPointSize() const
155{
156 return mUsesPointSize;
157}
158
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000159bool ProgramBinary::usesPointSpriteEmulation() const
160{
161 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
162}
163
164bool ProgramBinary::usesGeometryShader() const
165{
166 return usesPointSpriteEmulation();
167}
168
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000169// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
170// index (0-15 for the pixel shader and 0-3 for the vertex shader).
171GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
172{
173 GLint logicalTextureUnit = -1;
174
175 switch (type)
176 {
177 case SAMPLER_PIXEL:
178 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
179
180 if (mSamplersPS[samplerIndex].active)
181 {
182 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
183 }
184 break;
185 case SAMPLER_VERTEX:
186 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
187
188 if (mSamplersVS[samplerIndex].active)
189 {
190 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
191 }
192 break;
193 default: UNREACHABLE();
194 }
195
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000196 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000197 {
198 return logicalTextureUnit;
199 }
200
201 return -1;
202}
203
204// Returns the texture type for a given Direct3D 9 sampler type and
205// index (0-15 for the pixel shader and 0-3 for the vertex shader).
206TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
207{
208 switch (type)
209 {
210 case SAMPLER_PIXEL:
211 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
212 ASSERT(mSamplersPS[samplerIndex].active);
213 return mSamplersPS[samplerIndex].textureType;
214 case SAMPLER_VERTEX:
215 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
216 ASSERT(mSamplersVS[samplerIndex].active);
217 return mSamplersVS[samplerIndex].textureType;
218 default: UNREACHABLE();
219 }
220
221 return TEXTURE_2D;
222}
223
224GLint ProgramBinary::getUniformLocation(std::string name)
225{
226 unsigned int subscript = 0;
227
228 // Strip any trailing array operator and retrieve the subscript
229 size_t open = name.find_last_of('[');
230 size_t close = name.find_last_of(']');
231 if (open != std::string::npos && close == name.length() - 1)
232 {
233 subscript = atoi(name.substr(open + 1).c_str());
234 name.erase(open);
235 }
236
237 unsigned int numUniforms = mUniformIndex.size();
238 for (unsigned int location = 0; location < numUniforms; location++)
239 {
240 if (mUniformIndex[location].name == name &&
241 mUniformIndex[location].element == subscript)
242 {
243 return location;
244 }
245 }
246
247 return -1;
248}
249
250bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
251{
252 if (location < 0 || location >= (int)mUniformIndex.size())
253 {
254 return false;
255 }
256
257 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
258 targetUniform->dirty = true;
259
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000260 int elementCount = targetUniform->elementCount();
261
262 if (elementCount == 1 && count > 1)
263 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
264
265 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
266
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000267 if (targetUniform->type == GL_FLOAT)
268 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000269 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
270
271 for (int i = 0; i < count; i++)
272 {
273 target[0] = v[0];
274 target[1] = 0;
275 target[2] = 0;
276 target[3] = 0;
277 target += 4;
278 v += 1;
279 }
280 }
281 else if (targetUniform->type == GL_BOOL)
282 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000283 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000284
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000285 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000286 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000287 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
288 boolParams[1] = GL_FALSE;
289 boolParams[2] = GL_FALSE;
290 boolParams[3] = GL_FALSE;
291 boolParams += 4;
292 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000293 }
294 }
295 else
296 {
297 return false;
298 }
299
300 return true;
301}
302
303bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
304{
305 if (location < 0 || location >= (int)mUniformIndex.size())
306 {
307 return false;
308 }
309
310 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
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000320 if (targetUniform->type == GL_FLOAT_VEC2)
321 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000322 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
323
324 for (int i = 0; i < count; i++)
325 {
326 target[0] = v[0];
327 target[1] = v[1];
328 target[2] = 0;
329 target[3] = 0;
330 target += 4;
331 v += 2;
332 }
333 }
334 else if (targetUniform->type == GL_BOOL_VEC2)
335 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000336 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000337
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000338 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000339 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000340 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
341 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
342 boolParams[2] = GL_FALSE;
343 boolParams[3] = GL_FALSE;
344 boolParams += 4;
345 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000346 }
347 }
348 else
349 {
350 return false;
351 }
352
353 return true;
354}
355
356bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
357{
358 if (location < 0 || location >= (int)mUniformIndex.size())
359 {
360 return false;
361 }
362
363 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
364 targetUniform->dirty = true;
365
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000366 int elementCount = targetUniform->elementCount();
367
368 if (elementCount == 1 && count > 1)
369 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
370
371 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
372
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000373 if (targetUniform->type == GL_FLOAT_VEC3)
374 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000375 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
376
377 for (int i = 0; i < count; i++)
378 {
379 target[0] = v[0];
380 target[1] = v[1];
381 target[2] = v[2];
382 target[3] = 0;
383 target += 4;
384 v += 3;
385 }
386 }
387 else if (targetUniform->type == GL_BOOL_VEC3)
388 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000389 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000390
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000391 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000393 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
394 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
395 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
396 boolParams[3] = GL_FALSE;
397 boolParams += 4;
398 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399 }
400 }
401 else
402 {
403 return false;
404 }
405
406 return true;
407}
408
409bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
410{
411 if (location < 0 || location >= (int)mUniformIndex.size())
412 {
413 return false;
414 }
415
416 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
417 targetUniform->dirty = true;
418
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000419 int elementCount = targetUniform->elementCount();
420
421 if (elementCount == 1 && count > 1)
422 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
423
424 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
425
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000426 if (targetUniform->type == GL_FLOAT_VEC4)
427 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000428 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000429
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000430 for (int i = 0; i < count; i++)
431 {
432 target[0] = v[0];
433 target[1] = v[1];
434 target[2] = v[2];
435 target[3] = v[3];
436 target += 4;
437 v += 4;
438 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439 }
440 else if (targetUniform->type == GL_BOOL_VEC4)
441 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000442 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000443
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000444 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000446 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
447 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
448 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
449 boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
450 boolParams += 4;
451 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452 }
453 }
454 else
455 {
456 return false;
457 }
458
459 return true;
460}
461
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000462template<typename T>
463void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000464{
465 int copyWidth = std::min(targetWidth, srcWidth);
466 int copyHeight = std::min(targetHeight, srcHeight);
467
468 for (int x = 0; x < copyWidth; x++)
469 {
470 for (int y = 0; y < copyHeight; y++)
471 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000472 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000473 }
474 }
475 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000476 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000477 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000478 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000479 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000480 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000481 }
482 }
483 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000484 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000485 {
486 for (int x = 0; x < targetWidth; x++)
487 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000488 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000489 }
490 }
491}
492
493bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
494{
495 if (location < 0 || location >= (int)mUniformIndex.size())
496 {
497 return false;
498 }
499
500 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
501 targetUniform->dirty = true;
502
503 if (targetUniform->type != GL_FLOAT_MAT2)
504 {
505 return false;
506 }
507
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000508 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000509
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000510 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000511 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
512
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000513 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000514 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000515
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000516 for (int i = 0; i < count; i++)
517 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000518 transposeMatrix<GLfloat>(target, value, 4, 2, 2, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000519 target += 8;
520 value += 4;
521 }
522
523 return true;
524}
525
526bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
527{
528 if (location < 0 || location >= (int)mUniformIndex.size())
529 {
530 return false;
531 }
532
533 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
534 targetUniform->dirty = true;
535
536 if (targetUniform->type != GL_FLOAT_MAT3)
537 {
538 return false;
539 }
540
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000541 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000543 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000544 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
545
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000546 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000547 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000548
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000549 for (int i = 0; i < count; i++)
550 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000551 transposeMatrix<GLfloat>(target, value, 4, 3, 3, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000552 target += 12;
553 value += 9;
554 }
555
556 return true;
557}
558
559
560bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
561{
562 if (location < 0 || location >= (int)mUniformIndex.size())
563 {
564 return false;
565 }
566
567 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
568 targetUniform->dirty = true;
569
570 if (targetUniform->type != GL_FLOAT_MAT4)
571 {
572 return false;
573 }
574
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000575 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000576
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000577 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
579
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000580 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000581 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000582
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000583 for (int i = 0; i < count; i++)
584 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000585 transposeMatrix<GLfloat>(target, value, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000586 target += 16;
587 value += 16;
588 }
589
590 return true;
591}
592
593bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
594{
595 if (location < 0 || location >= (int)mUniformIndex.size())
596 {
597 return false;
598 }
599
600 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
601 targetUniform->dirty = true;
602
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000603 int elementCount = targetUniform->elementCount();
604
605 if (elementCount == 1 && count > 1)
606 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
607
608 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
609
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000610 if (targetUniform->type == GL_INT ||
611 targetUniform->type == GL_SAMPLER_2D ||
612 targetUniform->type == GL_SAMPLER_CUBE)
613 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000614 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000615
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000616 for (int i = 0; i < count; i++)
617 {
618 target[0] = v[0];
619 target[1] = 0;
620 target[2] = 0;
621 target[3] = 0;
622 target += 4;
623 v += 1;
624 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000625 }
626 else if (targetUniform->type == GL_BOOL)
627 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000628 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000630 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000632 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
633 boolParams[1] = GL_FALSE;
634 boolParams[2] = GL_FALSE;
635 boolParams[3] = GL_FALSE;
636 boolParams += 4;
637 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000638 }
639 }
640 else
641 {
642 return false;
643 }
644
645 return true;
646}
647
648bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
649{
650 if (location < 0 || location >= (int)mUniformIndex.size())
651 {
652 return false;
653 }
654
655 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
656 targetUniform->dirty = true;
657
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000658 int elementCount = targetUniform->elementCount();
659
660 if (elementCount == 1 && count > 1)
661 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
662
663 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
664
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665 if (targetUniform->type == GL_INT_VEC2)
666 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000667 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000669 for (int i = 0; i < count; i++)
670 {
671 target[0] = v[0];
672 target[1] = v[1];
673 target[2] = 0;
674 target[3] = 0;
675 target += 4;
676 v += 2;
677 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000678 }
679 else if (targetUniform->type == GL_BOOL_VEC2)
680 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000681 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000682
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000683 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000684 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000685 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
686 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
687 boolParams[2] = GL_FALSE;
688 boolParams[3] = GL_FALSE;
689 boolParams += 4;
690 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000691 }
692 }
693 else
694 {
695 return false;
696 }
697
698 return true;
699}
700
701bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
702{
703 if (location < 0 || location >= (int)mUniformIndex.size())
704 {
705 return false;
706 }
707
708 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
709 targetUniform->dirty = true;
710
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000711 int elementCount = targetUniform->elementCount();
712
713 if (elementCount == 1 && count > 1)
714 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
715
716 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
717
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000718 if (targetUniform->type == GL_INT_VEC3)
719 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000720 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000721
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000722 for (int i = 0; i < count; i++)
723 {
724 target[0] = v[0];
725 target[1] = v[1];
726 target[2] = v[2];
727 target[3] = 0;
728 target += 4;
729 v += 3;
730 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000731 }
732 else if (targetUniform->type == GL_BOOL_VEC3)
733 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000734 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000735
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000736 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000737 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000738 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
739 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
740 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
741 boolParams[3] = GL_FALSE;
742 boolParams += 4;
743 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000744 }
745 }
746 else
747 {
748 return false;
749 }
750
751 return true;
752}
753
754bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
755{
756 if (location < 0 || location >= (int)mUniformIndex.size())
757 {
758 return false;
759 }
760
761 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
762 targetUniform->dirty = true;
763
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000764 int elementCount = targetUniform->elementCount();
765
766 if (elementCount == 1 && count > 1)
767 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
768
769 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
770
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000771 if (targetUniform->type == GL_INT_VEC4)
772 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000773 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000774
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000775 for (int i = 0; i < count; i++)
776 {
777 target[0] = v[0];
778 target[1] = v[1];
779 target[2] = v[2];
780 target[3] = v[3];
781 target += 4;
782 v += 4;
783 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000784 }
785 else if (targetUniform->type == GL_BOOL_VEC4)
786 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000787 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000788
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000789 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000790 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000791 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
792 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
793 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
794 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
795 boolParams += 4;
796 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000797 }
798 }
799 else
800 {
801 return false;
802 }
803
804 return true;
805}
806
807bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
808{
809 if (location < 0 || location >= (int)mUniformIndex.size())
810 {
811 return false;
812 }
813
814 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
815
816 // sized queries -- ensure the provided buffer is large enough
817 if (bufSize)
818 {
819 int requiredBytes = UniformExternalSize(targetUniform->type);
820 if (*bufSize < requiredBytes)
821 {
822 return false;
823 }
824 }
825
826 switch (targetUniform->type)
827 {
828 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000829 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000830 break;
831 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000832 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000833 break;
834 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000835 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000836 break;
837 default:
838 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000839 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000840
841 switch (UniformComponentType(targetUniform->type))
842 {
843 case GL_BOOL:
844 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000845 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000846
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000847 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000848 {
849 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
850 }
851 }
852 break;
853 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000854 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
855 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000856 break;
857 case GL_INT:
858 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000859 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000860
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000861 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000862 {
863 params[i] = (float)intParams[i];
864 }
865 }
866 break;
867 default: UNREACHABLE();
868 }
869 }
870 }
871
872 return true;
873}
874
875bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
876{
877 if (location < 0 || location >= (int)mUniformIndex.size())
878 {
879 return false;
880 }
881
882 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
883
884 // sized queries -- ensure the provided buffer is large enough
885 if (bufSize)
886 {
887 int requiredBytes = UniformExternalSize(targetUniform->type);
888 if (*bufSize < requiredBytes)
889 {
890 return false;
891 }
892 }
893
894 switch (targetUniform->type)
895 {
896 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000897 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000898 break;
899 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000900 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000901 break;
902 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000903 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000904 break;
905 default:
906 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000907 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000908
909 switch (UniformComponentType(targetUniform->type))
910 {
911 case GL_BOOL:
912 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000913 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000914
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000915 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000916 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000917 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000918 }
919 }
920 break;
921 case GL_FLOAT:
922 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000923 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000924
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000925 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000926 {
927 params[i] = (GLint)floatParams[i];
928 }
929 }
930 break;
931 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000932 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
933 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000934 break;
935 default: UNREACHABLE();
936 }
937 }
938 }
939
940 return true;
941}
942
943void ProgramBinary::dirtyAllUniforms()
944{
945 unsigned int numUniforms = mUniforms.size();
946 for (unsigned int index = 0; index < numUniforms; index++)
947 {
948 mUniforms[index]->dirty = true;
949 }
950}
951
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000952// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000953void ProgramBinary::applyUniforms()
954{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000955 // Retrieve sampler uniform values
956 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
957 {
958 Uniform *targetUniform = *ub;
959
960 if (targetUniform->dirty)
961 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000962 if (targetUniform->type == GL_SAMPLER_2D ||
963 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000964 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000965 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000966 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000967
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000968 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000969 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000970 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000971
972 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000973 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000974 unsigned int samplerIndex = firstIndex + i;
975
976 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000977 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000978 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000979 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000980 }
981 }
982 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000983
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000984 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000985 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000986 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000987
988 for (int i = 0; i < count; i++)
989 {
990 unsigned int samplerIndex = firstIndex + i;
991
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000992 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000993 {
994 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000995 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000996 }
997 }
998 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000999 }
1000 }
1001 }
1002
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +00001003 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001004}
1005
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001006// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1007// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001008int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001009{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001010 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001011
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001012 fragmentShader->resetVaryingsRegisterAssignment();
1013
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001014 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1015 {
1016 int n = VariableRowCount(varying->type) * varying->size;
1017 int m = VariableColumnCount(varying->type);
1018 bool success = false;
1019
1020 if (m == 2 || m == 3 || m == 4)
1021 {
1022 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1023 {
1024 bool available = true;
1025
1026 for (int y = 0; y < n && available; y++)
1027 {
1028 for (int x = 0; x < m && available; x++)
1029 {
1030 if (packing[r + y][x])
1031 {
1032 available = false;
1033 }
1034 }
1035 }
1036
1037 if (available)
1038 {
1039 varying->reg = r;
1040 varying->col = 0;
1041
1042 for (int y = 0; y < n; y++)
1043 {
1044 for (int x = 0; x < m; x++)
1045 {
1046 packing[r + y][x] = &*varying;
1047 }
1048 }
1049
1050 success = true;
1051 }
1052 }
1053
1054 if (!success && m == 2)
1055 {
1056 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1057 {
1058 bool available = true;
1059
1060 for (int y = 0; y < n && available; y++)
1061 {
1062 for (int x = 2; x < 4 && available; x++)
1063 {
1064 if (packing[r + y][x])
1065 {
1066 available = false;
1067 }
1068 }
1069 }
1070
1071 if (available)
1072 {
1073 varying->reg = r;
1074 varying->col = 2;
1075
1076 for (int y = 0; y < n; y++)
1077 {
1078 for (int x = 2; x < 4; x++)
1079 {
1080 packing[r + y][x] = &*varying;
1081 }
1082 }
1083
1084 success = true;
1085 }
1086 }
1087 }
1088 }
1089 else if (m == 1)
1090 {
1091 int space[4] = {0};
1092
1093 for (int y = 0; y < maxVaryingVectors; y++)
1094 {
1095 for (int x = 0; x < 4; x++)
1096 {
1097 space[x] += packing[y][x] ? 0 : 1;
1098 }
1099 }
1100
1101 int column = 0;
1102
1103 for (int x = 0; x < 4; x++)
1104 {
1105 if (space[x] >= n && space[x] < space[column])
1106 {
1107 column = x;
1108 }
1109 }
1110
1111 if (space[column] >= n)
1112 {
1113 for (int r = 0; r < maxVaryingVectors; r++)
1114 {
1115 if (!packing[r][column])
1116 {
1117 varying->reg = r;
1118
1119 for (int y = r; y < r + n; y++)
1120 {
1121 packing[y][column] = &*varying;
1122 }
1123
1124 break;
1125 }
1126 }
1127
1128 varying->col = column;
1129
1130 success = true;
1131 }
1132 }
1133 else UNREACHABLE();
1134
1135 if (!success)
1136 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001137 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001138
1139 return -1;
1140 }
1141 }
1142
1143 // Return the number of used registers
1144 int registers = 0;
1145
1146 for (int r = 0; r < maxVaryingVectors; r++)
1147 {
1148 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1149 {
1150 registers++;
1151 }
1152 }
1153
1154 return registers;
1155}
1156
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001157bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1158 std::string& pixelHLSL, std::string& vertexHLSL,
1159 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001160{
1161 if (pixelHLSL.empty() || vertexHLSL.empty())
1162 {
1163 return false;
1164 }
1165
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001166 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1167 bool usesFragColor = fragmentShader->mUsesFragColor;
1168 bool usesFragData = fragmentShader->mUsesFragData;
1169 if (usesMRT && usesFragColor && usesFragData)
1170 {
1171 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1172 return false;
1173 }
1174
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001176 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001177 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001178
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001179 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1180
1181 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001182 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001183 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001184
1185 return false;
1186 }
1187
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001188 vertexShader->resetVaryingsRegisterAssignment();
1189
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001190 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1191 {
1192 bool matched = false;
1193
1194 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1195 {
1196 if (output->name == input->name)
1197 {
1198 if (output->type != input->type || output->size != input->size)
1199 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001200 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 +00001201
1202 return false;
1203 }
1204
1205 output->reg = input->reg;
1206 output->col = input->col;
1207
1208 matched = true;
1209 break;
1210 }
1211 }
1212
1213 if (!matched)
1214 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001215 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001216
1217 return false;
1218 }
1219 }
1220
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001221 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001222 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001223 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001224 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1225
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001226 const unsigned int renderTargetCount = usesMRT ? mRenderer->getMaxRenderTargets() : 1;
1227
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001228 // special varyings that use reserved registers
1229 int reservedRegisterIndex = registers;
1230 std::string fragCoordSemantic;
1231 std::string pointCoordSemantic;
1232
1233 if (fragmentShader->mUsesFragCoord)
1234 {
1235 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1236 }
1237
1238 if (fragmentShader->mUsesPointCoord)
1239 {
1240 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1241 // In DX11 we compute this in the GS.
1242 if (shaderModel == 3)
1243 {
1244 pointCoordSemantic = "TEXCOORD0";
1245 }
1246 else if (shaderModel >= 4)
1247 {
1248 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1249 }
1250 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001251
1252 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001253 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001254
1255 int semanticIndex = 0;
1256 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1257 {
1258 switch (attribute->type)
1259 {
1260 case GL_FLOAT: vertexHLSL += " float "; break;
1261 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1262 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1263 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1264 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1265 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1266 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1267 default: UNREACHABLE();
1268 }
1269
1270 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1271
1272 semanticIndex += VariableRowCount(attribute->type);
1273 }
1274
1275 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001276 "\n"
1277 "struct VS_OUTPUT\n"
1278 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001279
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001280 if (shaderModel < 4)
1281 {
1282 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1283 }
1284
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001285 for (int r = 0; r < registers; r++)
1286 {
1287 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1288
1289 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1290 }
1291
1292 if (fragmentShader->mUsesFragCoord)
1293 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001294 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295 }
1296
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001297 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298 {
1299 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1300 }
1301
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001302 if (shaderModel >= 4)
1303 {
1304 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1305 }
1306
1307 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001308 "\n"
1309 "VS_OUTPUT main(VS_INPUT input)\n"
1310 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001311
1312 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1313 {
1314 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1315
1316 if (VariableRowCount(attribute->type) > 1) // Matrix
1317 {
1318 vertexHLSL += "transpose";
1319 }
1320
1321 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1322 }
1323
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001324 if (shaderModel >= 4)
1325 {
1326 vertexHLSL += "\n"
1327 " gl_main();\n"
1328 "\n"
1329 " VS_OUTPUT output;\n"
1330 " output.gl_Position.x = gl_Position.x;\n"
1331 " output.gl_Position.y = -gl_Position.y;\n"
1332 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1333 " output.gl_Position.w = gl_Position.w;\n";
1334 }
1335 else
1336 {
1337 vertexHLSL += "\n"
1338 " gl_main();\n"
1339 "\n"
1340 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001341 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1342 " 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 +00001343 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1344 " output.gl_Position.w = gl_Position.w;\n";
1345 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001346
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001347 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001348 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001349 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001350 }
1351
1352 if (fragmentShader->mUsesFragCoord)
1353 {
1354 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1355 }
1356
1357 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1358 {
1359 if (varying->reg >= 0)
1360 {
1361 for (int i = 0; i < varying->size; i++)
1362 {
1363 int rows = VariableRowCount(varying->type);
1364
1365 for (int j = 0; j < rows; j++)
1366 {
1367 int r = varying->reg + i * rows + j;
1368 vertexHLSL += " output.v" + str(r);
1369
1370 bool sharedRegister = false; // Register used by multiple varyings
1371
1372 for (int x = 0; x < 4; x++)
1373 {
1374 if (packing[r][x] && packing[r][x] != packing[r][0])
1375 {
1376 sharedRegister = true;
1377 break;
1378 }
1379 }
1380
1381 if(sharedRegister)
1382 {
1383 vertexHLSL += ".";
1384
1385 for (int x = 0; x < 4; x++)
1386 {
1387 if (packing[r][x] == &*varying)
1388 {
1389 switch(x)
1390 {
1391 case 0: vertexHLSL += "x"; break;
1392 case 1: vertexHLSL += "y"; break;
1393 case 2: vertexHLSL += "z"; break;
1394 case 3: vertexHLSL += "w"; break;
1395 }
1396 }
1397 }
1398 }
1399
1400 vertexHLSL += " = " + varying->name;
1401
1402 if (varying->array)
1403 {
1404 vertexHLSL += "[" + str(i) + "]";
1405 }
1406
1407 if (rows > 1)
1408 {
1409 vertexHLSL += "[" + str(j) + "]";
1410 }
1411
1412 vertexHLSL += ";\n";
1413 }
1414 }
1415 }
1416 }
1417
1418 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001419 " return output;\n"
1420 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001421
1422 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001423 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001424
1425 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1426 {
1427 if (varying->reg >= 0)
1428 {
1429 for (int i = 0; i < varying->size; i++)
1430 {
1431 int rows = VariableRowCount(varying->type);
1432 for (int j = 0; j < rows; j++)
1433 {
1434 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001435 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001436 }
1437 }
1438 }
1439 else UNREACHABLE();
1440 }
1441
1442 if (fragmentShader->mUsesFragCoord)
1443 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001444 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001445 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001446
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001447 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1448 {
1449 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1450 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001451
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001452 // Must consume the PSIZE element if the geometry shader is not active
1453 // We won't know if we use a GS until we draw
1454 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1455 {
1456 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1457 }
1458
1459 if (fragmentShader->mUsesFragCoord)
1460 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001461 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001462 {
1463 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1464 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001465 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001466 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1468 }
1469 }
1470
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001471 pixelHLSL += "};\n"
1472 "\n"
1473 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001474 "{\n";
1475
1476 for (unsigned int i = 0; i < renderTargetCount; i++)
1477 {
1478 pixelHLSL += " float4 gl_Color" + str(i) + " : " + targetSemantic + str(i) + ";\n";
1479 }
1480
1481 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001482 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001483
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001484 if (fragmentShader->mUsesFrontFacing)
1485 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001486 if (shaderModel >= 4)
1487 {
1488 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1489 "{\n";
1490 }
1491 else
1492 {
1493 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1494 "{\n";
1495 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001496 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001497 else
1498 {
1499 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1500 "{\n";
1501 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001502
1503 if (fragmentShader->mUsesFragCoord)
1504 {
1505 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1506
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001507 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001508 {
1509 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1510 " gl_FragCoord.y = input.dx_VPos.y;\n";
1511 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001512 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001513 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001514 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001515 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001516 }
1517 else
1518 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001519 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1520 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1521 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001522 }
1523
daniel@transgaming.com12985182012-12-20 20:56:31 +00001524 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001525 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001526 }
1527
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001528 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001529 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001530 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1531 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001532 }
1533
1534 if (fragmentShader->mUsesFrontFacing)
1535 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001536 if (shaderModel <= 3)
1537 {
1538 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1539 }
1540 else
1541 {
1542 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1543 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001544 }
1545
1546 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1547 {
1548 if (varying->reg >= 0)
1549 {
1550 for (int i = 0; i < varying->size; i++)
1551 {
1552 int rows = VariableRowCount(varying->type);
1553 for (int j = 0; j < rows; j++)
1554 {
1555 std::string n = str(varying->reg + i * rows + j);
1556 pixelHLSL += " " + varying->name;
1557
1558 if (varying->array)
1559 {
1560 pixelHLSL += "[" + str(i) + "]";
1561 }
1562
1563 if (rows > 1)
1564 {
1565 pixelHLSL += "[" + str(j) + "]";
1566 }
1567
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001568 switch (VariableColumnCount(varying->type))
1569 {
1570 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1571 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1572 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1573 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1574 default: UNREACHABLE();
1575 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001576 }
1577 }
1578 }
1579 else UNREACHABLE();
1580 }
1581
1582 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001583 " gl_main();\n"
1584 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001585 " PS_OUTPUT output;\n";
1586
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001587 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1588 // - with a 3.0 context, the output color is copied to channel 0
1589 // - with a 2.0 context using EXT_draw_buffers, the output color is broadcast to all channels
1590 const bool broadcast = fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3;
1591
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001592 for (unsigned int i = 0; i < renderTargetCount; i++)
1593 {
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001594 unsigned int sourceColor = !broadcast ? i : 0;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001595
1596 pixelHLSL += " output.gl_Color" + str(i) + " = gl_Color[" + str(sourceColor) + "];\n";
1597 }
1598
1599 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001600 " return output;\n"
1601 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001602
1603 return true;
1604}
1605
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001606bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1607{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001608 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001609
1610 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001611 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001612 if (format != GL_PROGRAM_BINARY_ANGLE)
1613 {
1614 infoLog.append("Invalid program binary format.");
1615 return false;
1616 }
1617
1618 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001619 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001620 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621 {
1622 infoLog.append("Invalid program binary version.");
1623 return false;
1624 }
1625
1626 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1627 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001628 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001630 stream.read(&name);
1631 mLinkedAttribute[i].name = name;
1632 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633 }
1634
1635 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1636 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001637 stream.read(&mSamplersPS[i].active);
1638 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001639
1640 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001641 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001642 mSamplersPS[i].textureType = (TextureType) textureType;
1643 }
1644
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001645 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.read(&mSamplersVS[i].active);
1648 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649
1650 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001651 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001652 mSamplersVS[i].textureType = (TextureType) textureType;
1653 }
1654
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 stream.read(&mUsedVertexSamplerRange);
1656 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001657 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001658
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001659 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001660 stream.read(&size);
1661 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 {
1663 infoLog.append("Invalid program binary.");
1664 return false;
1665 }
1666
1667 mUniforms.resize(size);
1668 for (unsigned int i = 0; i < size; ++i)
1669 {
1670 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001671 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001672 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673 unsigned int arraySize;
1674
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001675 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001676 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001677 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001680 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001681
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001682 stream.read(&mUniforms[i]->psRegisterIndex);
1683 stream.read(&mUniforms[i]->vsRegisterIndex);
1684 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001685 }
1686
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001687 stream.read(&size);
1688 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001689 {
1690 infoLog.append("Invalid program binary.");
1691 return false;
1692 }
1693
1694 mUniformIndex.resize(size);
1695 for (unsigned int i = 0; i < size; ++i)
1696 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001697 stream.read(&mUniformIndex[i].name);
1698 stream.read(&mUniformIndex[i].element);
1699 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001700 }
1701
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001702 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001703 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704
1705 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001707
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001708 unsigned int geometryShaderSize;
1709 stream.read(&geometryShaderSize);
1710
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001711 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712
daniel@transgaming.com36038542012-11-28 20:59:26 +00001713 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001714 ptr += sizeof(GUID);
1715
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001716 GUID identifier = mRenderer->getAdapterIdentifier();
1717 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001718 {
1719 infoLog.append("Invalid program binary.");
1720 return false;
1721 }
1722
1723 const char *pixelShaderFunction = ptr;
1724 ptr += pixelShaderSize;
1725
1726 const char *vertexShaderFunction = ptr;
1727 ptr += vertexShaderSize;
1728
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001729 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1730 ptr += geometryShaderSize;
1731
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001732 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001733 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001734 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735 {
1736 infoLog.append("Could not create pixel shader.");
1737 return false;
1738 }
1739
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001740 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001741 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001742 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743 {
1744 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001745 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746 mPixelExecutable = NULL;
1747 return false;
1748 }
1749
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001750 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1751 {
1752 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1753 geometryShaderSize, rx::SHADER_GEOMETRY);
1754 if (!mGeometryExecutable)
1755 {
1756 infoLog.append("Could not create geometry shader.");
1757 delete mPixelExecutable;
1758 mPixelExecutable = NULL;
1759 delete mVertexExecutable;
1760 mVertexExecutable = NULL;
1761 return false;
1762 }
1763 }
1764 else
1765 {
1766 mGeometryExecutable = NULL;
1767 }
1768
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769 return true;
1770}
1771
1772bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1773{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001774 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001777 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778
1779 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1780 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(mLinkedAttribute[i].type);
1782 stream.write(mLinkedAttribute[i].name);
1783 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001784 }
1785
1786 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1787 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001788 stream.write(mSamplersPS[i].active);
1789 stream.write(mSamplersPS[i].logicalTextureUnit);
1790 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791 }
1792
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001793 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001795 stream.write(mSamplersVS[i].active);
1796 stream.write(mSamplersVS[i].logicalTextureUnit);
1797 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001798 }
1799
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001800 stream.write(mUsedVertexSamplerRange);
1801 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001802 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001803
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001804 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1806 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001807 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001808 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001809 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001810 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001811
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001812 stream.write(mUniforms[i]->psRegisterIndex);
1813 stream.write(mUniforms[i]->vsRegisterIndex);
1814 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001815 }
1816
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001817 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001818 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1819 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001820 stream.write(mUniformIndex[i].name);
1821 stream.write(mUniformIndex[i].element);
1822 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823 }
1824
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001825 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001826 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001827
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001828 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001829 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001830
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001831 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1832 stream.write(geometryShaderSize);
1833
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001834 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001835
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001836 GLsizei streamLength = stream.length();
1837 const void *streamData = stream.data();
1838
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001839 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001840 if (totalLength > bufSize)
1841 {
1842 if (length)
1843 {
1844 *length = 0;
1845 }
1846
1847 return false;
1848 }
1849
1850 if (binary)
1851 {
1852 char *ptr = (char*) binary;
1853
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001854 memcpy(ptr, streamData, streamLength);
1855 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001856
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001857 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001858 ptr += sizeof(GUID);
1859
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001860 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001861 ptr += pixelShaderSize;
1862
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001863 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001864 ptr += vertexShaderSize;
1865
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001866 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1867 {
1868 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1869 ptr += geometryShaderSize;
1870 }
1871
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001872 ASSERT(ptr - totalLength == binary);
1873 }
1874
1875 if (length)
1876 {
1877 *length = totalLength;
1878 }
1879
1880 return true;
1881}
1882
1883GLint ProgramBinary::getLength()
1884{
1885 GLint length;
1886 if (save(NULL, INT_MAX, &length))
1887 {
1888 return length;
1889 }
1890 else
1891 {
1892 return 0;
1893 }
1894}
1895
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001896bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001897{
1898 if (!fragmentShader || !fragmentShader->isCompiled())
1899 {
1900 return false;
1901 }
1902
1903 if (!vertexShader || !vertexShader->isCompiled())
1904 {
1905 return false;
1906 }
1907
1908 std::string pixelHLSL = fragmentShader->getHLSL();
1909 std::string vertexHLSL = vertexShader->getHLSL();
1910
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001911 // Map the varyings to the register file
1912 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1913 int registers = packVaryings(infoLog, packing, fragmentShader);
1914
1915 if (registers < 0)
1916 {
1917 return false;
1918 }
1919
1920 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001921 {
1922 return false;
1923 }
1924
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001925 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001926 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1927 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001928
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001929 if (usesGeometryShader())
1930 {
1931 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1932 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1933 }
1934
1935 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001936 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001937 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001938 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001939
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001940 delete mVertexExecutable;
1941 mVertexExecutable = NULL;
1942 delete mPixelExecutable;
1943 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001944 delete mGeometryExecutable;
1945 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001946 }
1947
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001948 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1949 {
1950 success = false;
1951 }
1952
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001953 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001954 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001955 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001956 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001957
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001958 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001959}
1960
1961// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001962bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001963{
1964 unsigned int usedLocations = 0;
1965
1966 // Link attributes that have a binding location
1967 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1968 {
1969 int location = attributeBindings.getAttributeBinding(attribute->name);
1970
1971 if (location != -1) // Set by glBindAttribLocation
1972 {
1973 if (!mLinkedAttribute[location].name.empty())
1974 {
1975 // Multiple active attributes bound to the same location; not an error
1976 }
1977
1978 mLinkedAttribute[location] = *attribute;
1979
1980 int rows = VariableRowCount(attribute->type);
1981
1982 if (rows + location > MAX_VERTEX_ATTRIBS)
1983 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001984 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 +00001985
1986 return false;
1987 }
1988
1989 for (int i = 0; i < rows; i++)
1990 {
1991 usedLocations |= 1 << (location + i);
1992 }
1993 }
1994 }
1995
1996 // Link attributes that don't have a binding location
1997 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1998 {
1999 int location = attributeBindings.getAttributeBinding(attribute->name);
2000
2001 if (location == -1) // Not set by glBindAttribLocation
2002 {
2003 int rows = VariableRowCount(attribute->type);
2004 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2005
2006 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2007 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002008 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002009
2010 return false; // Fail to link
2011 }
2012
2013 mLinkedAttribute[availableIndex] = *attribute;
2014 }
2015 }
2016
2017 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2018 {
2019 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2020 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2021
2022 for (int r = 0; r < rows; r++)
2023 {
2024 mSemanticIndex[attributeIndex++] = index++;
2025 }
2026 }
2027
2028 return true;
2029}
2030
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002031bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002032{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002033 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002034 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002035 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002036 {
2037 return false;
2038 }
2039 }
2040
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002041 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002042 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002043 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002044 {
2045 return false;
2046 }
2047 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002048
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002049 return true;
2050}
2051
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002052bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002053{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002054 if (constant.type == GL_SAMPLER_2D ||
2055 constant.type == GL_SAMPLER_CUBE)
2056 {
2057 unsigned int samplerIndex = constant.registerIndex;
2058
2059 do
2060 {
2061 if (shader == GL_VERTEX_SHADER)
2062 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002063 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002064 {
2065 mSamplersVS[samplerIndex].active = true;
2066 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2067 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2068 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2069 }
2070 else
2071 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002072 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002073 return false;
2074 }
2075 }
2076 else if (shader == GL_FRAGMENT_SHADER)
2077 {
2078 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2079 {
2080 mSamplersPS[samplerIndex].active = true;
2081 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2082 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2083 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2084 }
2085 else
2086 {
2087 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2088 return false;
2089 }
2090 }
2091 else UNREACHABLE();
2092
2093 samplerIndex++;
2094 }
2095 while (samplerIndex < constant.registerIndex + constant.arraySize);
2096 }
2097
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002098 Uniform *uniform = NULL;
2099 GLint location = getUniformLocation(constant.name);
2100
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002101 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002102 {
2103 uniform = mUniforms[mUniformIndex[location].index];
2104
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002105 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002106 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002107 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
2108 return false;
2109 }
2110
2111 if (uniform->precision != constant.precision)
2112 {
2113 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 +00002114 return false;
2115 }
2116 }
2117 else
2118 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002119 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002120 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002121
2122 if (!uniform)
2123 {
2124 return false;
2125 }
2126
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002127 if (shader == GL_FRAGMENT_SHADER)
2128 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002129 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002130 }
2131 else if (shader == GL_VERTEX_SHADER)
2132 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002133 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002134 }
2135 else UNREACHABLE();
2136
2137 if (location >= 0)
2138 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002139 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002140 }
2141
2142 mUniforms.push_back(uniform);
2143 unsigned int uniformIndex = mUniforms.size() - 1;
2144
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002145 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002146 {
2147 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2148 }
2149
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002150 if (shader == GL_VERTEX_SHADER)
2151 {
2152 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2153 {
2154 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2155 return false;
2156 }
2157 }
2158 else if (shader == GL_FRAGMENT_SHADER)
2159 {
2160 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2161 {
2162 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2163 return false;
2164 }
2165 }
2166 else UNREACHABLE();
2167
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002168 return true;
2169}
2170
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002171std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2172{
2173 // for now we only handle point sprite emulation
2174 ASSERT(usesPointSpriteEmulation());
2175 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2176}
2177
2178std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2179{
2180 ASSERT(registers >= 0);
2181 ASSERT(vertexShader->mUsesPointSize);
2182 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2183
2184 std::string geomHLSL;
2185
2186 std::string varyingSemantic = "TEXCOORD";
2187
2188 std::string fragCoordSemantic;
2189 std::string pointCoordSemantic;
2190
2191 int reservedRegisterIndex = registers;
2192
2193 if (fragmentShader->mUsesFragCoord)
2194 {
2195 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2196 }
2197
2198 if (fragmentShader->mUsesPointCoord)
2199 {
2200 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2201 }
2202
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002203 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2204 "\n"
2205 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002206 "{\n";
2207
2208 for (int r = 0; r < registers; r++)
2209 {
2210 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2211
2212 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2213 }
2214
2215 if (fragmentShader->mUsesFragCoord)
2216 {
2217 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2218 }
2219
2220 geomHLSL += " float gl_PointSize : PSIZE;\n"
2221 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002222 "};\n"
2223 "\n"
2224 "struct GS_OUTPUT\n"
2225 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002226
2227 for (int r = 0; r < registers; r++)
2228 {
2229 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2230
2231 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2232 }
2233
2234 if (fragmentShader->mUsesFragCoord)
2235 {
2236 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2237 }
2238
2239 if (fragmentShader->mUsesPointCoord)
2240 {
2241 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2242 }
2243
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002244 geomHLSL += " float gl_PointSize : PSIZE;\n"
2245 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002246 "};\n"
2247 "\n"
2248 "static float2 pointSpriteCorners[] = \n"
2249 "{\n"
2250 " float2( 0.5f, -0.5f),\n"
2251 " float2( 0.5f, 0.5f),\n"
2252 " float2(-0.5f, -0.5f),\n"
2253 " float2(-0.5f, 0.5f)\n"
2254 "};\n"
2255 "\n"
2256 "static float2 pointSpriteTexcoords[] = \n"
2257 "{\n"
2258 " float2(1.0f, 1.0f),\n"
2259 " float2(1.0f, 0.0f),\n"
2260 " float2(0.0f, 1.0f),\n"
2261 " float2(0.0f, 0.0f)\n"
2262 "};\n"
2263 "\n"
2264 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2265 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2266 "\n"
2267 "[maxvertexcount(4)]\n"
2268 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2269 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002270 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2271 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002272
2273 for (int r = 0; r < registers; r++)
2274 {
2275 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2276 }
2277
2278 if (fragmentShader->mUsesFragCoord)
2279 {
2280 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2281 }
2282
2283 geomHLSL += " \n"
2284 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2285 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002286 " 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 +00002287
2288 for (int corner = 0; corner < 4; corner++)
2289 {
2290 geomHLSL += " \n"
2291 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2292
2293 if (fragmentShader->mUsesPointCoord)
2294 {
2295 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2296 }
2297
2298 geomHLSL += " outStream.Append(output);\n";
2299 }
2300
2301 geomHLSL += " \n"
2302 " outStream.RestartStrip();\n"
2303 "}\n";
2304
2305 return geomHLSL;
2306}
2307
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002308// This method needs to match OutputHLSL::decorate
2309std::string ProgramBinary::decorateAttribute(const std::string &name)
2310{
2311 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2312 {
2313 return "_" + name;
2314 }
2315
2316 return name;
2317}
2318
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002319bool ProgramBinary::isValidated() const
2320{
2321 return mValidated;
2322}
2323
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002324void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002325{
2326 // Skip over inactive attributes
2327 unsigned int activeAttribute = 0;
2328 unsigned int attribute;
2329 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2330 {
2331 if (mLinkedAttribute[attribute].name.empty())
2332 {
2333 continue;
2334 }
2335
2336 if (activeAttribute == index)
2337 {
2338 break;
2339 }
2340
2341 activeAttribute++;
2342 }
2343
2344 if (bufsize > 0)
2345 {
2346 const char *string = mLinkedAttribute[attribute].name.c_str();
2347
2348 strncpy(name, string, bufsize);
2349 name[bufsize - 1] = '\0';
2350
2351 if (length)
2352 {
2353 *length = strlen(name);
2354 }
2355 }
2356
2357 *size = 1; // Always a single 'type' instance
2358
2359 *type = mLinkedAttribute[attribute].type;
2360}
2361
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002362GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002363{
2364 int count = 0;
2365
2366 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2367 {
2368 if (!mLinkedAttribute[attributeIndex].name.empty())
2369 {
2370 count++;
2371 }
2372 }
2373
2374 return count;
2375}
2376
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002377GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002378{
2379 int maxLength = 0;
2380
2381 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2382 {
2383 if (!mLinkedAttribute[attributeIndex].name.empty())
2384 {
2385 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2386 }
2387 }
2388
2389 return maxLength;
2390}
2391
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002392void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002393{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002394 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002395
2396 if (bufsize > 0)
2397 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002398 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002399
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002400 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002401 {
2402 string += "[0]";
2403 }
2404
2405 strncpy(name, string.c_str(), bufsize);
2406 name[bufsize - 1] = '\0';
2407
2408 if (length)
2409 {
2410 *length = strlen(name);
2411 }
2412 }
2413
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002414 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002415
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002416 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002417}
2418
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002419GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002420{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002421 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002422}
2423
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002424GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002425{
2426 int maxLength = 0;
2427
2428 unsigned int numUniforms = mUniforms.size();
2429 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2430 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002431 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002432 {
2433 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2434 if (mUniforms[uniformIndex]->isArray())
2435 {
2436 length += 3; // Counting in "[0]".
2437 }
2438 maxLength = std::max(length, maxLength);
2439 }
2440 }
2441
2442 return maxLength;
2443}
2444
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002445void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002446{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002447 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002448 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002449 {
2450 mValidated = false;
2451 }
2452 else
2453 {
2454 mValidated = true;
2455 }
2456}
2457
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002458bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002459{
2460 // if any two active samplers in a program are of different types, but refer to the same
2461 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2462 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2463
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002464 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002465 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002466
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002467 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002468 {
2469 textureUnitType[i] = TEXTURE_UNKNOWN;
2470 }
2471
2472 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2473 {
2474 if (mSamplersPS[i].active)
2475 {
2476 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2477
2478 if (unit >= maxCombinedTextureImageUnits)
2479 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002480 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002481 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002482 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002483 }
2484
2485 return false;
2486 }
2487
2488 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2489 {
2490 if (mSamplersPS[i].textureType != textureUnitType[unit])
2491 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002492 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002493 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002494 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002495 }
2496
2497 return false;
2498 }
2499 }
2500 else
2501 {
2502 textureUnitType[unit] = mSamplersPS[i].textureType;
2503 }
2504 }
2505 }
2506
2507 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2508 {
2509 if (mSamplersVS[i].active)
2510 {
2511 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2512
2513 if (unit >= maxCombinedTextureImageUnits)
2514 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002515 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002516 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002517 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002518 }
2519
2520 return false;
2521 }
2522
2523 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2524 {
2525 if (mSamplersVS[i].textureType != textureUnitType[unit])
2526 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002527 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002528 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002529 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002530 }
2531
2532 return false;
2533 }
2534 }
2535 else
2536 {
2537 textureUnitType[unit] = mSamplersVS[i].textureType;
2538 }
2539 }
2540 }
2541
2542 return true;
2543}
2544
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002545ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2546{
2547}
2548
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002549struct AttributeSorter
2550{
2551 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2552 : originalIndices(semanticIndices)
2553 {
2554 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2555 {
2556 indices[i] = i;
2557 }
2558
2559 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2560 }
2561
2562 bool operator()(int a, int b)
2563 {
2564 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2565 }
2566
2567 int indices[MAX_VERTEX_ATTRIBS];
2568 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2569};
2570
2571void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2572{
2573 AttributeSorter sorter(mSemanticIndex);
2574
2575 int oldIndices[MAX_VERTEX_ATTRIBS];
2576 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2577
2578 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2579 {
2580 oldIndices[i] = mSemanticIndex[i];
2581 oldTranslatedAttributes[i] = attributes[i];
2582 }
2583
2584 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2585 {
2586 int oldIndex = sorter.indices[i];
2587 sortedSemanticIndices[i] = oldIndices[oldIndex];
2588 attributes[i] = oldTranslatedAttributes[oldIndex];
2589 }
2590}
2591
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002592}