blob: a654c6b4cf1072dd2e945377f4a097c4d7bf3754 [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
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000493template <int cols, int rows>
494bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000495{
496 if (location < 0 || location >= (int)mUniformIndex.size())
497 {
498 return false;
499 }
500
501 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
502 targetUniform->dirty = true;
503
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000504 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000505 {
506 return false;
507 }
508
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000509 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000510
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000511 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000512 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
513
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000514 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000515 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4 * rows);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000516
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000517 for (int i = 0; i < count; i++)
518 {
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000519 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
520 target += 4 * rows;
521 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000522 }
523
524 return true;
525}
526
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000527bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
528{
529 return setUniformMatrixfv<2, 2>(location, count, value, GL_FLOAT_MAT2);
530}
531
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000532bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
533{
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000534 return setUniformMatrixfv<3, 3>(location, count, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000535}
536
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000537bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
538{
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000539 return setUniformMatrixfv<4, 4>(location, count, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000540}
541
542bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
543{
544 if (location < 0 || location >= (int)mUniformIndex.size())
545 {
546 return false;
547 }
548
549 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
550 targetUniform->dirty = true;
551
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000552 int elementCount = targetUniform->elementCount();
553
554 if (elementCount == 1 && count > 1)
555 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
556
557 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
558
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559 if (targetUniform->type == GL_INT ||
560 targetUniform->type == GL_SAMPLER_2D ||
561 targetUniform->type == GL_SAMPLER_CUBE)
562 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000563 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000564
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000565 for (int i = 0; i < count; i++)
566 {
567 target[0] = v[0];
568 target[1] = 0;
569 target[2] = 0;
570 target[3] = 0;
571 target += 4;
572 v += 1;
573 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000574 }
575 else if (targetUniform->type == GL_BOOL)
576 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000577 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000579 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000580 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000581 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
582 boolParams[1] = GL_FALSE;
583 boolParams[2] = GL_FALSE;
584 boolParams[3] = GL_FALSE;
585 boolParams += 4;
586 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000587 }
588 }
589 else
590 {
591 return false;
592 }
593
594 return true;
595}
596
597bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
598{
599 if (location < 0 || location >= (int)mUniformIndex.size())
600 {
601 return false;
602 }
603
604 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
605 targetUniform->dirty = true;
606
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000607 int elementCount = targetUniform->elementCount();
608
609 if (elementCount == 1 && count > 1)
610 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
611
612 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
613
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614 if (targetUniform->type == GL_INT_VEC2)
615 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000616 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000617
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000618 for (int i = 0; i < count; i++)
619 {
620 target[0] = v[0];
621 target[1] = v[1];
622 target[2] = 0;
623 target[3] = 0;
624 target += 4;
625 v += 2;
626 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000627 }
628 else if (targetUniform->type == GL_BOOL_VEC2)
629 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000630 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000632 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000633 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000634 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
635 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
636 boolParams[2] = GL_FALSE;
637 boolParams[3] = GL_FALSE;
638 boolParams += 4;
639 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000640 }
641 }
642 else
643 {
644 return false;
645 }
646
647 return true;
648}
649
650bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
651{
652 if (location < 0 || location >= (int)mUniformIndex.size())
653 {
654 return false;
655 }
656
657 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
658 targetUniform->dirty = true;
659
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000660 int elementCount = targetUniform->elementCount();
661
662 if (elementCount == 1 && count > 1)
663 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
664
665 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
666
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667 if (targetUniform->type == GL_INT_VEC3)
668 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000669 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000670
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000671 for (int i = 0; i < count; i++)
672 {
673 target[0] = v[0];
674 target[1] = v[1];
675 target[2] = v[2];
676 target[3] = 0;
677 target += 4;
678 v += 3;
679 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000680 }
681 else if (targetUniform->type == GL_BOOL_VEC3)
682 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000683 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000684
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000685 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000686 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000687 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
688 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
689 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
690 boolParams[3] = GL_FALSE;
691 boolParams += 4;
692 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693 }
694 }
695 else
696 {
697 return false;
698 }
699
700 return true;
701}
702
703bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
704{
705 if (location < 0 || location >= (int)mUniformIndex.size())
706 {
707 return false;
708 }
709
710 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
711 targetUniform->dirty = true;
712
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000713 int elementCount = targetUniform->elementCount();
714
715 if (elementCount == 1 && count > 1)
716 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
717
718 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
719
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720 if (targetUniform->type == GL_INT_VEC4)
721 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000722 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000723
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000724 for (int i = 0; i < count; i++)
725 {
726 target[0] = v[0];
727 target[1] = v[1];
728 target[2] = v[2];
729 target[3] = v[3];
730 target += 4;
731 v += 4;
732 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733 }
734 else if (targetUniform->type == GL_BOOL_VEC4)
735 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000736 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000737
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000738 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000739 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000740 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
741 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
742 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
743 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
744 boolParams += 4;
745 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000746 }
747 }
748 else
749 {
750 return false;
751 }
752
753 return true;
754}
755
756bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
757{
758 if (location < 0 || location >= (int)mUniformIndex.size())
759 {
760 return false;
761 }
762
763 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
764
765 // sized queries -- ensure the provided buffer is large enough
766 if (bufSize)
767 {
768 int requiredBytes = UniformExternalSize(targetUniform->type);
769 if (*bufSize < requiredBytes)
770 {
771 return false;
772 }
773 }
774
775 switch (targetUniform->type)
776 {
777 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000778 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000779 break;
780 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000781 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000782 break;
783 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000784 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000785 break;
786 default:
787 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000788 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789
790 switch (UniformComponentType(targetUniform->type))
791 {
792 case GL_BOOL:
793 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000794 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000795
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000796 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000797 {
798 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
799 }
800 }
801 break;
802 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000803 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
804 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000805 break;
806 case GL_INT:
807 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000808 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000809
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000810 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000811 {
812 params[i] = (float)intParams[i];
813 }
814 }
815 break;
816 default: UNREACHABLE();
817 }
818 }
819 }
820
821 return true;
822}
823
824bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
825{
826 if (location < 0 || location >= (int)mUniformIndex.size())
827 {
828 return false;
829 }
830
831 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
832
833 // sized queries -- ensure the provided buffer is large enough
834 if (bufSize)
835 {
836 int requiredBytes = UniformExternalSize(targetUniform->type);
837 if (*bufSize < requiredBytes)
838 {
839 return false;
840 }
841 }
842
843 switch (targetUniform->type)
844 {
845 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000846 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000847 break;
848 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000849 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000850 break;
851 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000852 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000853 break;
854 default:
855 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000856 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000857
858 switch (UniformComponentType(targetUniform->type))
859 {
860 case GL_BOOL:
861 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000862 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000863
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000864 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000865 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000866 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000867 }
868 }
869 break;
870 case GL_FLOAT:
871 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000872 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000873
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000874 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000875 {
876 params[i] = (GLint)floatParams[i];
877 }
878 }
879 break;
880 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000881 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
882 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000883 break;
884 default: UNREACHABLE();
885 }
886 }
887 }
888
889 return true;
890}
891
892void ProgramBinary::dirtyAllUniforms()
893{
894 unsigned int numUniforms = mUniforms.size();
895 for (unsigned int index = 0; index < numUniforms; index++)
896 {
897 mUniforms[index]->dirty = true;
898 }
899}
900
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000901// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000902void ProgramBinary::applyUniforms()
903{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000904 // Retrieve sampler uniform values
905 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
906 {
907 Uniform *targetUniform = *ub;
908
909 if (targetUniform->dirty)
910 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000911 if (targetUniform->type == GL_SAMPLER_2D ||
912 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000913 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000914 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000915 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000916
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000917 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000918 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000919 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000920
921 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000922 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000923 unsigned int samplerIndex = firstIndex + i;
924
925 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000926 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000927 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000928 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000929 }
930 }
931 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000932
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000933 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000934 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000935 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000936
937 for (int i = 0; i < count; i++)
938 {
939 unsigned int samplerIndex = firstIndex + i;
940
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000941 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000942 {
943 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000944 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000945 }
946 }
947 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000948 }
949 }
950 }
951
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000952 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000953}
954
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000955// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
956// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000957int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000958{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000959 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000960
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000961 fragmentShader->resetVaryingsRegisterAssignment();
962
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000963 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
964 {
965 int n = VariableRowCount(varying->type) * varying->size;
966 int m = VariableColumnCount(varying->type);
967 bool success = false;
968
969 if (m == 2 || m == 3 || m == 4)
970 {
971 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
972 {
973 bool available = true;
974
975 for (int y = 0; y < n && available; y++)
976 {
977 for (int x = 0; x < m && available; x++)
978 {
979 if (packing[r + y][x])
980 {
981 available = false;
982 }
983 }
984 }
985
986 if (available)
987 {
988 varying->reg = r;
989 varying->col = 0;
990
991 for (int y = 0; y < n; y++)
992 {
993 for (int x = 0; x < m; x++)
994 {
995 packing[r + y][x] = &*varying;
996 }
997 }
998
999 success = true;
1000 }
1001 }
1002
1003 if (!success && m == 2)
1004 {
1005 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1006 {
1007 bool available = true;
1008
1009 for (int y = 0; y < n && available; y++)
1010 {
1011 for (int x = 2; x < 4 && available; x++)
1012 {
1013 if (packing[r + y][x])
1014 {
1015 available = false;
1016 }
1017 }
1018 }
1019
1020 if (available)
1021 {
1022 varying->reg = r;
1023 varying->col = 2;
1024
1025 for (int y = 0; y < n; y++)
1026 {
1027 for (int x = 2; x < 4; x++)
1028 {
1029 packing[r + y][x] = &*varying;
1030 }
1031 }
1032
1033 success = true;
1034 }
1035 }
1036 }
1037 }
1038 else if (m == 1)
1039 {
1040 int space[4] = {0};
1041
1042 for (int y = 0; y < maxVaryingVectors; y++)
1043 {
1044 for (int x = 0; x < 4; x++)
1045 {
1046 space[x] += packing[y][x] ? 0 : 1;
1047 }
1048 }
1049
1050 int column = 0;
1051
1052 for (int x = 0; x < 4; x++)
1053 {
1054 if (space[x] >= n && space[x] < space[column])
1055 {
1056 column = x;
1057 }
1058 }
1059
1060 if (space[column] >= n)
1061 {
1062 for (int r = 0; r < maxVaryingVectors; r++)
1063 {
1064 if (!packing[r][column])
1065 {
1066 varying->reg = r;
1067
1068 for (int y = r; y < r + n; y++)
1069 {
1070 packing[y][column] = &*varying;
1071 }
1072
1073 break;
1074 }
1075 }
1076
1077 varying->col = column;
1078
1079 success = true;
1080 }
1081 }
1082 else UNREACHABLE();
1083
1084 if (!success)
1085 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001086 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001087
1088 return -1;
1089 }
1090 }
1091
1092 // Return the number of used registers
1093 int registers = 0;
1094
1095 for (int r = 0; r < maxVaryingVectors; r++)
1096 {
1097 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1098 {
1099 registers++;
1100 }
1101 }
1102
1103 return registers;
1104}
1105
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001106bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1107 std::string& pixelHLSL, std::string& vertexHLSL,
1108 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001109{
1110 if (pixelHLSL.empty() || vertexHLSL.empty())
1111 {
1112 return false;
1113 }
1114
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001115 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1116 bool usesFragColor = fragmentShader->mUsesFragColor;
1117 bool usesFragData = fragmentShader->mUsesFragData;
1118 if (usesMRT && usesFragColor && usesFragData)
1119 {
1120 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1121 return false;
1122 }
1123
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001124 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001125 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001126 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001127
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001128 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1129
1130 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001131 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001132 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001133
1134 return false;
1135 }
1136
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001137 vertexShader->resetVaryingsRegisterAssignment();
1138
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001139 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1140 {
1141 bool matched = false;
1142
1143 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1144 {
1145 if (output->name == input->name)
1146 {
1147 if (output->type != input->type || output->size != input->size)
1148 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001149 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 +00001150
1151 return false;
1152 }
1153
1154 output->reg = input->reg;
1155 output->col = input->col;
1156
1157 matched = true;
1158 break;
1159 }
1160 }
1161
1162 if (!matched)
1163 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001164 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001165
1166 return false;
1167 }
1168 }
1169
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001170 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001171 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001172 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001173 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1174
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001175 const unsigned int renderTargetCount = usesMRT ? mRenderer->getMaxRenderTargets() : 1;
1176
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001177 // special varyings that use reserved registers
1178 int reservedRegisterIndex = registers;
1179 std::string fragCoordSemantic;
1180 std::string pointCoordSemantic;
1181
1182 if (fragmentShader->mUsesFragCoord)
1183 {
1184 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1185 }
1186
1187 if (fragmentShader->mUsesPointCoord)
1188 {
1189 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1190 // In DX11 we compute this in the GS.
1191 if (shaderModel == 3)
1192 {
1193 pointCoordSemantic = "TEXCOORD0";
1194 }
1195 else if (shaderModel >= 4)
1196 {
1197 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1198 }
1199 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001200
1201 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001202 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001203
1204 int semanticIndex = 0;
1205 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1206 {
1207 switch (attribute->type)
1208 {
1209 case GL_FLOAT: vertexHLSL += " float "; break;
1210 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1211 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1212 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1213 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1214 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1215 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1216 default: UNREACHABLE();
1217 }
1218
1219 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1220
1221 semanticIndex += VariableRowCount(attribute->type);
1222 }
1223
1224 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001225 "\n"
1226 "struct VS_OUTPUT\n"
1227 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001228
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001229 if (shaderModel < 4)
1230 {
1231 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1232 }
1233
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234 for (int r = 0; r < registers; r++)
1235 {
1236 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1237
1238 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1239 }
1240
1241 if (fragmentShader->mUsesFragCoord)
1242 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001243 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001244 }
1245
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001246 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001247 {
1248 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1249 }
1250
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001251 if (shaderModel >= 4)
1252 {
1253 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1254 }
1255
1256 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001257 "\n"
1258 "VS_OUTPUT main(VS_INPUT input)\n"
1259 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001260
1261 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1262 {
1263 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1264
1265 if (VariableRowCount(attribute->type) > 1) // Matrix
1266 {
1267 vertexHLSL += "transpose";
1268 }
1269
1270 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1271 }
1272
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001273 if (shaderModel >= 4)
1274 {
1275 vertexHLSL += "\n"
1276 " gl_main();\n"
1277 "\n"
1278 " VS_OUTPUT output;\n"
1279 " output.gl_Position.x = gl_Position.x;\n"
1280 " output.gl_Position.y = -gl_Position.y;\n"
1281 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1282 " output.gl_Position.w = gl_Position.w;\n";
1283 }
1284 else
1285 {
1286 vertexHLSL += "\n"
1287 " gl_main();\n"
1288 "\n"
1289 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001290 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1291 " 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 +00001292 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1293 " output.gl_Position.w = gl_Position.w;\n";
1294 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001296 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001297 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001298 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001299 }
1300
1301 if (fragmentShader->mUsesFragCoord)
1302 {
1303 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1304 }
1305
1306 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1307 {
1308 if (varying->reg >= 0)
1309 {
1310 for (int i = 0; i < varying->size; i++)
1311 {
1312 int rows = VariableRowCount(varying->type);
1313
1314 for (int j = 0; j < rows; j++)
1315 {
1316 int r = varying->reg + i * rows + j;
1317 vertexHLSL += " output.v" + str(r);
1318
1319 bool sharedRegister = false; // Register used by multiple varyings
1320
1321 for (int x = 0; x < 4; x++)
1322 {
1323 if (packing[r][x] && packing[r][x] != packing[r][0])
1324 {
1325 sharedRegister = true;
1326 break;
1327 }
1328 }
1329
1330 if(sharedRegister)
1331 {
1332 vertexHLSL += ".";
1333
1334 for (int x = 0; x < 4; x++)
1335 {
1336 if (packing[r][x] == &*varying)
1337 {
1338 switch(x)
1339 {
1340 case 0: vertexHLSL += "x"; break;
1341 case 1: vertexHLSL += "y"; break;
1342 case 2: vertexHLSL += "z"; break;
1343 case 3: vertexHLSL += "w"; break;
1344 }
1345 }
1346 }
1347 }
1348
1349 vertexHLSL += " = " + varying->name;
1350
1351 if (varying->array)
1352 {
1353 vertexHLSL += "[" + str(i) + "]";
1354 }
1355
1356 if (rows > 1)
1357 {
1358 vertexHLSL += "[" + str(j) + "]";
1359 }
1360
1361 vertexHLSL += ";\n";
1362 }
1363 }
1364 }
1365 }
1366
1367 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001368 " return output;\n"
1369 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001370
1371 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001372 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001373
1374 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1375 {
1376 if (varying->reg >= 0)
1377 {
1378 for (int i = 0; i < varying->size; i++)
1379 {
1380 int rows = VariableRowCount(varying->type);
1381 for (int j = 0; j < rows; j++)
1382 {
1383 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001384 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001385 }
1386 }
1387 }
1388 else UNREACHABLE();
1389 }
1390
1391 if (fragmentShader->mUsesFragCoord)
1392 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001393 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001394 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001395
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001396 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1397 {
1398 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1399 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001400
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001401 // Must consume the PSIZE element if the geometry shader is not active
1402 // We won't know if we use a GS until we draw
1403 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1404 {
1405 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1406 }
1407
1408 if (fragmentShader->mUsesFragCoord)
1409 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001410 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001411 {
1412 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1413 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001414 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001415 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001416 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1417 }
1418 }
1419
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001420 pixelHLSL += "};\n"
1421 "\n"
1422 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001423 "{\n";
1424
1425 for (unsigned int i = 0; i < renderTargetCount; i++)
1426 {
1427 pixelHLSL += " float4 gl_Color" + str(i) + " : " + targetSemantic + str(i) + ";\n";
1428 }
1429
1430 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001431 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001432
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001433 if (fragmentShader->mUsesFrontFacing)
1434 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001435 if (shaderModel >= 4)
1436 {
1437 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1438 "{\n";
1439 }
1440 else
1441 {
1442 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1443 "{\n";
1444 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001445 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001446 else
1447 {
1448 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1449 "{\n";
1450 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451
1452 if (fragmentShader->mUsesFragCoord)
1453 {
1454 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1455
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001456 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001457 {
1458 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1459 " gl_FragCoord.y = input.dx_VPos.y;\n";
1460 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001461 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001462 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001463 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001464 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001465 }
1466 else
1467 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001468 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1469 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1470 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001471 }
1472
daniel@transgaming.com12985182012-12-20 20:56:31 +00001473 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001474 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001475 }
1476
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001477 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001478 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001479 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1480 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001481 }
1482
1483 if (fragmentShader->mUsesFrontFacing)
1484 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001485 if (shaderModel <= 3)
1486 {
1487 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1488 }
1489 else
1490 {
1491 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1492 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001493 }
1494
1495 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1496 {
1497 if (varying->reg >= 0)
1498 {
1499 for (int i = 0; i < varying->size; i++)
1500 {
1501 int rows = VariableRowCount(varying->type);
1502 for (int j = 0; j < rows; j++)
1503 {
1504 std::string n = str(varying->reg + i * rows + j);
1505 pixelHLSL += " " + varying->name;
1506
1507 if (varying->array)
1508 {
1509 pixelHLSL += "[" + str(i) + "]";
1510 }
1511
1512 if (rows > 1)
1513 {
1514 pixelHLSL += "[" + str(j) + "]";
1515 }
1516
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001517 switch (VariableColumnCount(varying->type))
1518 {
1519 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1520 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1521 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1522 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1523 default: UNREACHABLE();
1524 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001525 }
1526 }
1527 }
1528 else UNREACHABLE();
1529 }
1530
1531 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001532 " gl_main();\n"
1533 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001534 " PS_OUTPUT output;\n";
1535
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001536 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1537 // - with a 3.0 context, the output color is copied to channel 0
1538 // - with a 2.0 context using EXT_draw_buffers, the output color is broadcast to all channels
1539 const bool broadcast = fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3;
1540
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001541 for (unsigned int i = 0; i < renderTargetCount; i++)
1542 {
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001543 unsigned int sourceColor = !broadcast ? i : 0;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001544
1545 pixelHLSL += " output.gl_Color" + str(i) + " = gl_Color[" + str(sourceColor) + "];\n";
1546 }
1547
1548 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001549 " return output;\n"
1550 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001551
1552 return true;
1553}
1554
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1556{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001557 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001558
1559 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001560 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561 if (format != GL_PROGRAM_BINARY_ANGLE)
1562 {
1563 infoLog.append("Invalid program binary format.");
1564 return false;
1565 }
1566
1567 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001568 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001569 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001570 {
1571 infoLog.append("Invalid program binary version.");
1572 return false;
1573 }
1574
1575 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1576 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001577 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001579 stream.read(&name);
1580 mLinkedAttribute[i].name = name;
1581 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001582 }
1583
1584 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1585 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001586 stream.read(&mSamplersPS[i].active);
1587 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001588
1589 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001590 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001591 mSamplersPS[i].textureType = (TextureType) textureType;
1592 }
1593
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001594 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001595 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001596 stream.read(&mSamplersVS[i].active);
1597 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598
1599 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001600 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601 mSamplersVS[i].textureType = (TextureType) textureType;
1602 }
1603
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001604 stream.read(&mUsedVertexSamplerRange);
1605 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001606 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001607
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001608 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001609 stream.read(&size);
1610 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001611 {
1612 infoLog.append("Invalid program binary.");
1613 return false;
1614 }
1615
1616 mUniforms.resize(size);
1617 for (unsigned int i = 0; i < size; ++i)
1618 {
1619 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001620 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001621 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001622 unsigned int arraySize;
1623
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001625 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001626 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001627 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001628
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001629 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001630
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001631 stream.read(&mUniforms[i]->psRegisterIndex);
1632 stream.read(&mUniforms[i]->vsRegisterIndex);
1633 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 }
1635
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001636 stream.read(&size);
1637 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 {
1639 infoLog.append("Invalid program binary.");
1640 return false;
1641 }
1642
1643 mUniformIndex.resize(size);
1644 for (unsigned int i = 0; i < size; ++i)
1645 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001646 stream.read(&mUniformIndex[i].name);
1647 stream.read(&mUniformIndex[i].element);
1648 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649 }
1650
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001652 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001653
1654 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001657 unsigned int geometryShaderSize;
1658 stream.read(&geometryShaderSize);
1659
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001660 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661
daniel@transgaming.com36038542012-11-28 20:59:26 +00001662 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001663 ptr += sizeof(GUID);
1664
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001665 GUID identifier = mRenderer->getAdapterIdentifier();
1666 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667 {
1668 infoLog.append("Invalid program binary.");
1669 return false;
1670 }
1671
1672 const char *pixelShaderFunction = ptr;
1673 ptr += pixelShaderSize;
1674
1675 const char *vertexShaderFunction = ptr;
1676 ptr += vertexShaderSize;
1677
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001678 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1679 ptr += geometryShaderSize;
1680
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001681 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001682 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001683 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684 {
1685 infoLog.append("Could not create pixel shader.");
1686 return false;
1687 }
1688
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001689 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001690 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001691 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001692 {
1693 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001694 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001695 mPixelExecutable = NULL;
1696 return false;
1697 }
1698
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001699 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1700 {
1701 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1702 geometryShaderSize, rx::SHADER_GEOMETRY);
1703 if (!mGeometryExecutable)
1704 {
1705 infoLog.append("Could not create geometry shader.");
1706 delete mPixelExecutable;
1707 mPixelExecutable = NULL;
1708 delete mVertexExecutable;
1709 mVertexExecutable = NULL;
1710 return false;
1711 }
1712 }
1713 else
1714 {
1715 mGeometryExecutable = NULL;
1716 }
1717
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001718 return true;
1719}
1720
1721bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1722{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001723 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001724
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001725 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001726 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001727
1728 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1729 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001730 stream.write(mLinkedAttribute[i].type);
1731 stream.write(mLinkedAttribute[i].name);
1732 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001733 }
1734
1735 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1736 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001737 stream.write(mSamplersPS[i].active);
1738 stream.write(mSamplersPS[i].logicalTextureUnit);
1739 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740 }
1741
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001742 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001744 stream.write(mSamplersVS[i].active);
1745 stream.write(mSamplersVS[i].logicalTextureUnit);
1746 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001747 }
1748
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001749 stream.write(mUsedVertexSamplerRange);
1750 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001751 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001753 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1755 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001756 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001757 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001758 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001759 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001761 stream.write(mUniforms[i]->psRegisterIndex);
1762 stream.write(mUniforms[i]->vsRegisterIndex);
1763 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764 }
1765
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1768 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001769 stream.write(mUniformIndex[i].name);
1770 stream.write(mUniformIndex[i].element);
1771 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772 }
1773
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001774 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001775 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001777 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001778 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001780 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1781 stream.write(geometryShaderSize);
1782
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001783 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001784
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 GLsizei streamLength = stream.length();
1786 const void *streamData = stream.data();
1787
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001788 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001789 if (totalLength > bufSize)
1790 {
1791 if (length)
1792 {
1793 *length = 0;
1794 }
1795
1796 return false;
1797 }
1798
1799 if (binary)
1800 {
1801 char *ptr = (char*) binary;
1802
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001803 memcpy(ptr, streamData, streamLength);
1804 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001806 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001807 ptr += sizeof(GUID);
1808
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001809 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001810 ptr += pixelShaderSize;
1811
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001812 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 ptr += vertexShaderSize;
1814
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001815 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1816 {
1817 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1818 ptr += geometryShaderSize;
1819 }
1820
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001821 ASSERT(ptr - totalLength == binary);
1822 }
1823
1824 if (length)
1825 {
1826 *length = totalLength;
1827 }
1828
1829 return true;
1830}
1831
1832GLint ProgramBinary::getLength()
1833{
1834 GLint length;
1835 if (save(NULL, INT_MAX, &length))
1836 {
1837 return length;
1838 }
1839 else
1840 {
1841 return 0;
1842 }
1843}
1844
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001845bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001846{
1847 if (!fragmentShader || !fragmentShader->isCompiled())
1848 {
1849 return false;
1850 }
1851
1852 if (!vertexShader || !vertexShader->isCompiled())
1853 {
1854 return false;
1855 }
1856
1857 std::string pixelHLSL = fragmentShader->getHLSL();
1858 std::string vertexHLSL = vertexShader->getHLSL();
1859
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001860 // Map the varyings to the register file
1861 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1862 int registers = packVaryings(infoLog, packing, fragmentShader);
1863
1864 if (registers < 0)
1865 {
1866 return false;
1867 }
1868
1869 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001870 {
1871 return false;
1872 }
1873
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001874 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001875 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1876 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001877
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001878 if (usesGeometryShader())
1879 {
1880 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1881 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1882 }
1883
1884 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001885 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001886 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001887 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001888
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001889 delete mVertexExecutable;
1890 mVertexExecutable = NULL;
1891 delete mPixelExecutable;
1892 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001893 delete mGeometryExecutable;
1894 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001895 }
1896
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001897 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1898 {
1899 success = false;
1900 }
1901
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001902 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001903 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001904 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001905 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001906
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001907 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001908}
1909
1910// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001911bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001912{
1913 unsigned int usedLocations = 0;
1914
1915 // Link attributes that have a binding location
1916 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1917 {
1918 int location = attributeBindings.getAttributeBinding(attribute->name);
1919
1920 if (location != -1) // Set by glBindAttribLocation
1921 {
1922 if (!mLinkedAttribute[location].name.empty())
1923 {
1924 // Multiple active attributes bound to the same location; not an error
1925 }
1926
1927 mLinkedAttribute[location] = *attribute;
1928
1929 int rows = VariableRowCount(attribute->type);
1930
1931 if (rows + location > MAX_VERTEX_ATTRIBS)
1932 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001933 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 +00001934
1935 return false;
1936 }
1937
1938 for (int i = 0; i < rows; i++)
1939 {
1940 usedLocations |= 1 << (location + i);
1941 }
1942 }
1943 }
1944
1945 // Link attributes that don't have a binding location
1946 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1947 {
1948 int location = attributeBindings.getAttributeBinding(attribute->name);
1949
1950 if (location == -1) // Not set by glBindAttribLocation
1951 {
1952 int rows = VariableRowCount(attribute->type);
1953 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1954
1955 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1956 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001957 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001958
1959 return false; // Fail to link
1960 }
1961
1962 mLinkedAttribute[availableIndex] = *attribute;
1963 }
1964 }
1965
1966 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1967 {
1968 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1969 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1970
1971 for (int r = 0; r < rows; r++)
1972 {
1973 mSemanticIndex[attributeIndex++] = index++;
1974 }
1975 }
1976
1977 return true;
1978}
1979
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001980bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001981{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001982 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001983 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001984 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001985 {
1986 return false;
1987 }
1988 }
1989
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001990 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001991 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001992 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001993 {
1994 return false;
1995 }
1996 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001997
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001998 return true;
1999}
2000
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002001bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002002{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002003 if (constant.type == GL_SAMPLER_2D ||
2004 constant.type == GL_SAMPLER_CUBE)
2005 {
2006 unsigned int samplerIndex = constant.registerIndex;
2007
2008 do
2009 {
2010 if (shader == GL_VERTEX_SHADER)
2011 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002012 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002013 {
2014 mSamplersVS[samplerIndex].active = true;
2015 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2016 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2017 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2018 }
2019 else
2020 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002021 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002022 return false;
2023 }
2024 }
2025 else if (shader == GL_FRAGMENT_SHADER)
2026 {
2027 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2028 {
2029 mSamplersPS[samplerIndex].active = true;
2030 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2031 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2032 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2033 }
2034 else
2035 {
2036 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2037 return false;
2038 }
2039 }
2040 else UNREACHABLE();
2041
2042 samplerIndex++;
2043 }
2044 while (samplerIndex < constant.registerIndex + constant.arraySize);
2045 }
2046
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002047 Uniform *uniform = NULL;
2048 GLint location = getUniformLocation(constant.name);
2049
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002050 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002051 {
2052 uniform = mUniforms[mUniformIndex[location].index];
2053
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002054 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002055 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002056 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
2057 return false;
2058 }
2059
2060 if (uniform->precision != constant.precision)
2061 {
2062 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 +00002063 return false;
2064 }
2065 }
2066 else
2067 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002068 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002069 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002070
2071 if (!uniform)
2072 {
2073 return false;
2074 }
2075
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002076 if (shader == GL_FRAGMENT_SHADER)
2077 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002078 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002079 }
2080 else if (shader == GL_VERTEX_SHADER)
2081 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002082 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002083 }
2084 else UNREACHABLE();
2085
2086 if (location >= 0)
2087 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002088 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002089 }
2090
2091 mUniforms.push_back(uniform);
2092 unsigned int uniformIndex = mUniforms.size() - 1;
2093
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002094 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002095 {
2096 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2097 }
2098
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002099 if (shader == GL_VERTEX_SHADER)
2100 {
2101 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2102 {
2103 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2104 return false;
2105 }
2106 }
2107 else if (shader == GL_FRAGMENT_SHADER)
2108 {
2109 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2110 {
2111 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2112 return false;
2113 }
2114 }
2115 else UNREACHABLE();
2116
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002117 return true;
2118}
2119
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002120std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2121{
2122 // for now we only handle point sprite emulation
2123 ASSERT(usesPointSpriteEmulation());
2124 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2125}
2126
2127std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2128{
2129 ASSERT(registers >= 0);
2130 ASSERT(vertexShader->mUsesPointSize);
2131 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2132
2133 std::string geomHLSL;
2134
2135 std::string varyingSemantic = "TEXCOORD";
2136
2137 std::string fragCoordSemantic;
2138 std::string pointCoordSemantic;
2139
2140 int reservedRegisterIndex = registers;
2141
2142 if (fragmentShader->mUsesFragCoord)
2143 {
2144 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2145 }
2146
2147 if (fragmentShader->mUsesPointCoord)
2148 {
2149 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2150 }
2151
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002152 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2153 "\n"
2154 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002155 "{\n";
2156
2157 for (int r = 0; r < registers; r++)
2158 {
2159 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2160
2161 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2162 }
2163
2164 if (fragmentShader->mUsesFragCoord)
2165 {
2166 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2167 }
2168
2169 geomHLSL += " float gl_PointSize : PSIZE;\n"
2170 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002171 "};\n"
2172 "\n"
2173 "struct GS_OUTPUT\n"
2174 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002175
2176 for (int r = 0; r < registers; r++)
2177 {
2178 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2179
2180 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2181 }
2182
2183 if (fragmentShader->mUsesFragCoord)
2184 {
2185 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2186 }
2187
2188 if (fragmentShader->mUsesPointCoord)
2189 {
2190 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2191 }
2192
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002193 geomHLSL += " float gl_PointSize : PSIZE;\n"
2194 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002195 "};\n"
2196 "\n"
2197 "static float2 pointSpriteCorners[] = \n"
2198 "{\n"
2199 " float2( 0.5f, -0.5f),\n"
2200 " float2( 0.5f, 0.5f),\n"
2201 " float2(-0.5f, -0.5f),\n"
2202 " float2(-0.5f, 0.5f)\n"
2203 "};\n"
2204 "\n"
2205 "static float2 pointSpriteTexcoords[] = \n"
2206 "{\n"
2207 " float2(1.0f, 1.0f),\n"
2208 " float2(1.0f, 0.0f),\n"
2209 " float2(0.0f, 1.0f),\n"
2210 " float2(0.0f, 0.0f)\n"
2211 "};\n"
2212 "\n"
2213 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2214 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2215 "\n"
2216 "[maxvertexcount(4)]\n"
2217 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2218 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002219 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2220 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002221
2222 for (int r = 0; r < registers; r++)
2223 {
2224 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2225 }
2226
2227 if (fragmentShader->mUsesFragCoord)
2228 {
2229 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2230 }
2231
2232 geomHLSL += " \n"
2233 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2234 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002235 " 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 +00002236
2237 for (int corner = 0; corner < 4; corner++)
2238 {
2239 geomHLSL += " \n"
2240 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2241
2242 if (fragmentShader->mUsesPointCoord)
2243 {
2244 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2245 }
2246
2247 geomHLSL += " outStream.Append(output);\n";
2248 }
2249
2250 geomHLSL += " \n"
2251 " outStream.RestartStrip();\n"
2252 "}\n";
2253
2254 return geomHLSL;
2255}
2256
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002257// This method needs to match OutputHLSL::decorate
2258std::string ProgramBinary::decorateAttribute(const std::string &name)
2259{
2260 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2261 {
2262 return "_" + name;
2263 }
2264
2265 return name;
2266}
2267
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002268bool ProgramBinary::isValidated() const
2269{
2270 return mValidated;
2271}
2272
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002273void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274{
2275 // Skip over inactive attributes
2276 unsigned int activeAttribute = 0;
2277 unsigned int attribute;
2278 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2279 {
2280 if (mLinkedAttribute[attribute].name.empty())
2281 {
2282 continue;
2283 }
2284
2285 if (activeAttribute == index)
2286 {
2287 break;
2288 }
2289
2290 activeAttribute++;
2291 }
2292
2293 if (bufsize > 0)
2294 {
2295 const char *string = mLinkedAttribute[attribute].name.c_str();
2296
2297 strncpy(name, string, bufsize);
2298 name[bufsize - 1] = '\0';
2299
2300 if (length)
2301 {
2302 *length = strlen(name);
2303 }
2304 }
2305
2306 *size = 1; // Always a single 'type' instance
2307
2308 *type = mLinkedAttribute[attribute].type;
2309}
2310
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002311GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002312{
2313 int count = 0;
2314
2315 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2316 {
2317 if (!mLinkedAttribute[attributeIndex].name.empty())
2318 {
2319 count++;
2320 }
2321 }
2322
2323 return count;
2324}
2325
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002326GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002327{
2328 int maxLength = 0;
2329
2330 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2331 {
2332 if (!mLinkedAttribute[attributeIndex].name.empty())
2333 {
2334 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2335 }
2336 }
2337
2338 return maxLength;
2339}
2340
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002341void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002342{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002343 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002344
2345 if (bufsize > 0)
2346 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002347 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002348
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002349 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002350 {
2351 string += "[0]";
2352 }
2353
2354 strncpy(name, string.c_str(), bufsize);
2355 name[bufsize - 1] = '\0';
2356
2357 if (length)
2358 {
2359 *length = strlen(name);
2360 }
2361 }
2362
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002363 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002364
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002365 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002366}
2367
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002368GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002369{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002370 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002371}
2372
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002373GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002374{
2375 int maxLength = 0;
2376
2377 unsigned int numUniforms = mUniforms.size();
2378 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2379 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002380 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002381 {
2382 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2383 if (mUniforms[uniformIndex]->isArray())
2384 {
2385 length += 3; // Counting in "[0]".
2386 }
2387 maxLength = std::max(length, maxLength);
2388 }
2389 }
2390
2391 return maxLength;
2392}
2393
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002394void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002395{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002396 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002397 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002398 {
2399 mValidated = false;
2400 }
2401 else
2402 {
2403 mValidated = true;
2404 }
2405}
2406
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002407bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002408{
2409 // if any two active samplers in a program are of different types, but refer to the same
2410 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2411 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2412
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002413 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002414 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002415
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002416 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002417 {
2418 textureUnitType[i] = TEXTURE_UNKNOWN;
2419 }
2420
2421 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2422 {
2423 if (mSamplersPS[i].active)
2424 {
2425 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2426
2427 if (unit >= maxCombinedTextureImageUnits)
2428 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002429 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002430 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002431 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002432 }
2433
2434 return false;
2435 }
2436
2437 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2438 {
2439 if (mSamplersPS[i].textureType != textureUnitType[unit])
2440 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002441 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002442 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002443 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002444 }
2445
2446 return false;
2447 }
2448 }
2449 else
2450 {
2451 textureUnitType[unit] = mSamplersPS[i].textureType;
2452 }
2453 }
2454 }
2455
2456 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2457 {
2458 if (mSamplersVS[i].active)
2459 {
2460 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2461
2462 if (unit >= maxCombinedTextureImageUnits)
2463 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002464 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002465 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002466 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002467 }
2468
2469 return false;
2470 }
2471
2472 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2473 {
2474 if (mSamplersVS[i].textureType != textureUnitType[unit])
2475 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002476 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002477 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002478 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002479 }
2480
2481 return false;
2482 }
2483 }
2484 else
2485 {
2486 textureUnitType[unit] = mSamplersVS[i].textureType;
2487 }
2488 }
2489 }
2490
2491 return true;
2492}
2493
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002494ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2495{
2496}
2497
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002498struct AttributeSorter
2499{
2500 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2501 : originalIndices(semanticIndices)
2502 {
2503 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2504 {
2505 indices[i] = i;
2506 }
2507
2508 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2509 }
2510
2511 bool operator()(int a, int b)
2512 {
2513 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2514 }
2515
2516 int indices[MAX_VERTEX_ATTRIBS];
2517 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2518};
2519
2520void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2521{
2522 AttributeSorter sorter(mSemanticIndex);
2523
2524 int oldIndices[MAX_VERTEX_ATTRIBS];
2525 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2526
2527 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2528 {
2529 oldIndices[i] = mSemanticIndex[i];
2530 oldTranslatedAttributes[i] = attributes[i];
2531 }
2532
2533 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2534 {
2535 int oldIndex = sorter.indices[i];
2536 sortedSemanticIndices[i] = oldIndices[oldIndex];
2537 attributes[i] = oldTranslatedAttributes[oldIndex];
2538 }
2539}
2540
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002541}