blob: 5f557c8723decb2f05c791d9001f7d9ce48ea82f [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
12
13#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000014#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000015
16#include "libGLESv2/main.h"
17#include "libGLESv2/Shader.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include <string>
20
daniel@transgaming.com88853c52012-12-20 20:56:40 +000021#undef near
22#undef far
23
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000024namespace gl
25{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000026std::string str(int i)
27{
28 char buffer[20];
29 snprintf(buffer, sizeof(buffer), "%d", i);
30 return buffer;
31}
32
daniel@transgaming.comdb019952012-12-20 21:13:32 +000033UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
34 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000035{
36}
37
daniel@transgaming.come87ca002012-07-24 18:30:43 +000038unsigned int ProgramBinary::mCurrentSerial = 1;
39
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000040ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000041{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000042 mPixelExecutable = NULL;
43 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000044 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000045
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046 mValidated = false;
47
48 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
49 {
50 mSemanticIndex[index] = -1;
51 }
52
53 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
54 {
55 mSamplersPS[index].active = false;
56 }
57
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000058 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000059 {
60 mSamplersVS[index].active = false;
61 }
62
63 mUsedVertexSamplerRange = 0;
64 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000065 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000066}
67
68ProgramBinary::~ProgramBinary()
69{
daniel@transgaming.com95892412012-11-28 20:59:09 +000070 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000071 mPixelExecutable = NULL;
72
daniel@transgaming.com95892412012-11-28 20:59:09 +000073 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000074 mVertexExecutable = NULL;
75
76 delete mGeometryExecutable;
77 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000078
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000079 while (!mUniforms.empty())
80 {
81 delete mUniforms.back();
82 mUniforms.pop_back();
83 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000084}
85
daniel@transgaming.come87ca002012-07-24 18:30:43 +000086unsigned int ProgramBinary::getSerial() const
87{
88 return mSerial;
89}
90
91unsigned int ProgramBinary::issueSerial()
92{
93 return mCurrentSerial++;
94}
95
daniel@transgaming.com95892412012-11-28 20:59:09 +000096rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097{
98 return mPixelExecutable;
99}
100
daniel@transgaming.com95892412012-11-28 20:59:09 +0000101rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102{
103 return mVertexExecutable;
104}
105
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000106rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
107{
108 return mGeometryExecutable;
109}
110
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000111GLuint ProgramBinary::getAttributeLocation(const char *name)
112{
113 if (name)
114 {
115 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
116 {
117 if (mLinkedAttribute[index].name == std::string(name))
118 {
119 return index;
120 }
121 }
122 }
123
124 return -1;
125}
126
127int ProgramBinary::getSemanticIndex(int attributeIndex)
128{
129 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
130
131 return mSemanticIndex[attributeIndex];
132}
133
134// Returns one more than the highest sampler index used.
135GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
136{
137 switch (type)
138 {
139 case SAMPLER_PIXEL:
140 return mUsedPixelSamplerRange;
141 case SAMPLER_VERTEX:
142 return mUsedVertexSamplerRange;
143 default:
144 UNREACHABLE();
145 return 0;
146 }
147}
148
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000149bool ProgramBinary::usesPointSize() const
150{
151 return mUsesPointSize;
152}
153
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000154bool ProgramBinary::usesPointSpriteEmulation() const
155{
156 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
157}
158
159bool ProgramBinary::usesGeometryShader() const
160{
161 return usesPointSpriteEmulation();
162}
163
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000164// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
165// index (0-15 for the pixel shader and 0-3 for the vertex shader).
166GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
167{
168 GLint logicalTextureUnit = -1;
169
170 switch (type)
171 {
172 case SAMPLER_PIXEL:
173 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
174
175 if (mSamplersPS[samplerIndex].active)
176 {
177 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
178 }
179 break;
180 case SAMPLER_VERTEX:
181 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
182
183 if (mSamplersVS[samplerIndex].active)
184 {
185 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
186 }
187 break;
188 default: UNREACHABLE();
189 }
190
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000191 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000192 {
193 return logicalTextureUnit;
194 }
195
196 return -1;
197}
198
199// Returns the texture type for a given Direct3D 9 sampler type and
200// index (0-15 for the pixel shader and 0-3 for the vertex shader).
201TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
202{
203 switch (type)
204 {
205 case SAMPLER_PIXEL:
206 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
207 ASSERT(mSamplersPS[samplerIndex].active);
208 return mSamplersPS[samplerIndex].textureType;
209 case SAMPLER_VERTEX:
210 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
211 ASSERT(mSamplersVS[samplerIndex].active);
212 return mSamplersVS[samplerIndex].textureType;
213 default: UNREACHABLE();
214 }
215
216 return TEXTURE_2D;
217}
218
219GLint ProgramBinary::getUniformLocation(std::string name)
220{
221 unsigned int subscript = 0;
222
223 // Strip any trailing array operator and retrieve the subscript
224 size_t open = name.find_last_of('[');
225 size_t close = name.find_last_of(']');
226 if (open != std::string::npos && close == name.length() - 1)
227 {
228 subscript = atoi(name.substr(open + 1).c_str());
229 name.erase(open);
230 }
231
232 unsigned int numUniforms = mUniformIndex.size();
233 for (unsigned int location = 0; location < numUniforms; location++)
234 {
235 if (mUniformIndex[location].name == name &&
236 mUniformIndex[location].element == subscript)
237 {
238 return location;
239 }
240 }
241
242 return -1;
243}
244
245bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
246{
247 if (location < 0 || location >= (int)mUniformIndex.size())
248 {
249 return false;
250 }
251
252 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
253 targetUniform->dirty = true;
254
255 if (targetUniform->type == GL_FLOAT)
256 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000257 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000258
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000259 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000260 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
261
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000262 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000263 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
264
265 for (int i = 0; i < count; i++)
266 {
267 target[0] = v[0];
268 target[1] = 0;
269 target[2] = 0;
270 target[3] = 0;
271 target += 4;
272 v += 1;
273 }
274 }
275 else if (targetUniform->type == GL_BOOL)
276 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000277 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000278
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000279 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000280 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
281
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000282 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
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
313 if (targetUniform->type == GL_FLOAT_VEC2)
314 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000315 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000316
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000317 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000318 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
319
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000320 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000321 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
322
323 for (int i = 0; i < count; i++)
324 {
325 target[0] = v[0];
326 target[1] = v[1];
327 target[2] = 0;
328 target[3] = 0;
329 target += 4;
330 v += 2;
331 }
332 }
333 else if (targetUniform->type == GL_BOOL_VEC2)
334 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000335 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000336
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000337 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000338 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
339
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000340 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000341 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000342
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000343 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000344 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000345 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
346 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
347 boolParams[2] = GL_FALSE;
348 boolParams[3] = GL_FALSE;
349 boolParams += 4;
350 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000351 }
352 }
353 else
354 {
355 return false;
356 }
357
358 return true;
359}
360
361bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
362{
363 if (location < 0 || location >= (int)mUniformIndex.size())
364 {
365 return false;
366 }
367
368 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
369 targetUniform->dirty = true;
370
371 if (targetUniform->type == GL_FLOAT_VEC3)
372 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000373 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000374
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000375 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000376 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
377
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000378 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000379 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
380
381 for (int i = 0; i < count; i++)
382 {
383 target[0] = v[0];
384 target[1] = v[1];
385 target[2] = v[2];
386 target[3] = 0;
387 target += 4;
388 v += 3;
389 }
390 }
391 else if (targetUniform->type == GL_BOOL_VEC3)
392 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000393 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000395 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000396 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
397
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000398 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000399 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000400
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000401 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000402 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000403 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
404 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
405 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
406 boolParams[3] = GL_FALSE;
407 boolParams += 4;
408 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000409 }
410 }
411 else
412 {
413 return false;
414 }
415
416 return true;
417}
418
419bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
420{
421 if (location < 0 || location >= (int)mUniformIndex.size())
422 {
423 return false;
424 }
425
426 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
427 targetUniform->dirty = true;
428
429 if (targetUniform->type == GL_FLOAT_VEC4)
430 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000431 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000432
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000433 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000434 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
435
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000436 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000437 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000439 for (int i = 0; i < count; i++)
440 {
441 target[0] = v[0];
442 target[1] = v[1];
443 target[2] = v[2];
444 target[3] = v[3];
445 target += 4;
446 v += 4;
447 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448 }
449 else if (targetUniform->type == GL_BOOL_VEC4)
450 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000451 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000453 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000454 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
455
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000456 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000457 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000458
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000459 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000460 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000461 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
462 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
463 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
464 boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
465 boolParams += 4;
466 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000467 }
468 }
469 else
470 {
471 return false;
472 }
473
474 return true;
475}
476
477template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
478void transposeMatrix(T *target, const GLfloat *value)
479{
480 int copyWidth = std::min(targetWidth, srcWidth);
481 int copyHeight = std::min(targetHeight, srcHeight);
482
483 for (int x = 0; x < copyWidth; x++)
484 {
485 for (int y = 0; y < copyHeight; y++)
486 {
487 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
488 }
489 }
490 // clear unfilled right side
491 for (int y = 0; y < copyHeight; y++)
492 {
493 for (int x = srcWidth; x < targetWidth; x++)
494 {
495 target[y * targetWidth + x] = (T)0;
496 }
497 }
498 // clear unfilled bottom.
499 for (int y = srcHeight; y < targetHeight; y++)
500 {
501 for (int x = 0; x < targetWidth; x++)
502 {
503 target[y * targetWidth + x] = (T)0;
504 }
505 }
506}
507
508bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
509{
510 if (location < 0 || location >= (int)mUniformIndex.size())
511 {
512 return false;
513 }
514
515 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
516 targetUniform->dirty = true;
517
518 if (targetUniform->type != GL_FLOAT_MAT2)
519 {
520 return false;
521 }
522
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000523 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000525 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000526 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
527
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000528 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000530
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000531 for (int i = 0; i < count; i++)
532 {
533 transposeMatrix<GLfloat,4,2,2,2>(target, value);
534 target += 8;
535 value += 4;
536 }
537
538 return true;
539}
540
541bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
542{
543 if (location < 0 || location >= (int)mUniformIndex.size())
544 {
545 return false;
546 }
547
548 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
549 targetUniform->dirty = true;
550
551 if (targetUniform->type != GL_FLOAT_MAT3)
552 {
553 return false;
554 }
555
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000556 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000557
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000558 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
560
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000561 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000563
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000564 for (int i = 0; i < count; i++)
565 {
566 transposeMatrix<GLfloat,4,3,3,3>(target, value);
567 target += 12;
568 value += 9;
569 }
570
571 return true;
572}
573
574
575bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
576{
577 if (location < 0 || location >= (int)mUniformIndex.size())
578 {
579 return false;
580 }
581
582 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
583 targetUniform->dirty = true;
584
585 if (targetUniform->type != GL_FLOAT_MAT4)
586 {
587 return false;
588 }
589
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000590 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000591
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000592 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000593 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
594
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000595 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000596 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000597
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000598 for (int i = 0; i < count; i++)
599 {
600 transposeMatrix<GLfloat,4,4,4,4>(target, value);
601 target += 16;
602 value += 16;
603 }
604
605 return true;
606}
607
608bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
609{
610 if (location < 0 || location >= (int)mUniformIndex.size())
611 {
612 return false;
613 }
614
615 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
616 targetUniform->dirty = true;
617
618 if (targetUniform->type == GL_INT ||
619 targetUniform->type == GL_SAMPLER_2D ||
620 targetUniform->type == GL_SAMPLER_CUBE)
621 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000622 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000623
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000624 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000625 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
626
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000627 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000628 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000630 for (int i = 0; i < count; i++)
631 {
632 target[0] = v[0];
633 target[1] = 0;
634 target[2] = 0;
635 target[3] = 0;
636 target += 4;
637 v += 1;
638 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000639 }
640 else if (targetUniform->type == GL_BOOL)
641 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000642 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000643
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000644 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000645 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
646
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000647 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000648 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000649
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000650 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000651 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000652 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
653 boolParams[1] = GL_FALSE;
654 boolParams[2] = GL_FALSE;
655 boolParams[3] = GL_FALSE;
656 boolParams += 4;
657 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000658 }
659 }
660 else
661 {
662 return false;
663 }
664
665 return true;
666}
667
668bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
669{
670 if (location < 0 || location >= (int)mUniformIndex.size())
671 {
672 return false;
673 }
674
675 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
676 targetUniform->dirty = true;
677
678 if (targetUniform->type == GL_INT_VEC2)
679 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000680 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000681
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000682 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000683 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
684
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000685 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000686 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000687
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000688 for (int i = 0; i < count; i++)
689 {
690 target[0] = v[0];
691 target[1] = v[1];
692 target[2] = 0;
693 target[3] = 0;
694 target += 4;
695 v += 2;
696 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697 }
698 else if (targetUniform->type == GL_BOOL_VEC2)
699 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000700 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000701
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000702 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000703 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
704
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000705 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000706 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000707
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000708 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000709 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000710 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
711 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
712 boolParams[2] = GL_FALSE;
713 boolParams[3] = GL_FALSE;
714 boolParams += 4;
715 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000716 }
717 }
718 else
719 {
720 return false;
721 }
722
723 return true;
724}
725
726bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
727{
728 if (location < 0 || location >= (int)mUniformIndex.size())
729 {
730 return false;
731 }
732
733 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
734 targetUniform->dirty = true;
735
736 if (targetUniform->type == GL_INT_VEC3)
737 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000738 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000739
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000740 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000741 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
742
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000743 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000744 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000745
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000746 for (int i = 0; i < count; i++)
747 {
748 target[0] = v[0];
749 target[1] = v[1];
750 target[2] = v[2];
751 target[3] = 0;
752 target += 4;
753 v += 3;
754 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755 }
756 else if (targetUniform->type == GL_BOOL_VEC3)
757 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000758 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000759
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000760 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
762
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000763 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000764 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000765
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000766 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000767 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000768 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
769 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
770 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
771 boolParams[3] = GL_FALSE;
772 boolParams += 4;
773 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000774 }
775 }
776 else
777 {
778 return false;
779 }
780
781 return true;
782}
783
784bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
785{
786 if (location < 0 || location >= (int)mUniformIndex.size())
787 {
788 return false;
789 }
790
791 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
792 targetUniform->dirty = true;
793
794 if (targetUniform->type == GL_INT_VEC4)
795 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000796 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000797
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000798 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000799 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
800
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000801 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000802 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000803
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000804 for (int i = 0; i < count; i++)
805 {
806 target[0] = v[0];
807 target[1] = v[1];
808 target[2] = v[2];
809 target[3] = v[3];
810 target += 4;
811 v += 4;
812 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000813 }
814 else if (targetUniform->type == GL_BOOL_VEC4)
815 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000816 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000817
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000818 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000819 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
820
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000821 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000822 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000823
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000824 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000825 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000826 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
827 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
828 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
829 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
830 boolParams += 4;
831 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000832 }
833 }
834 else
835 {
836 return false;
837 }
838
839 return true;
840}
841
842bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
843{
844 if (location < 0 || location >= (int)mUniformIndex.size())
845 {
846 return false;
847 }
848
849 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
850
851 // sized queries -- ensure the provided buffer is large enough
852 if (bufSize)
853 {
854 int requiredBytes = UniformExternalSize(targetUniform->type);
855 if (*bufSize < requiredBytes)
856 {
857 return false;
858 }
859 }
860
861 switch (targetUniform->type)
862 {
863 case GL_FLOAT_MAT2:
864 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
865 break;
866 case GL_FLOAT_MAT3:
867 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
868 break;
869 case GL_FLOAT_MAT4:
870 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
871 break;
872 default:
873 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000874 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000875
876 switch (UniformComponentType(targetUniform->type))
877 {
878 case GL_BOOL:
879 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000880 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000881
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000882 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000883 {
884 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
885 }
886 }
887 break;
888 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000889 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
890 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000891 break;
892 case GL_INT:
893 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000894 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000895
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000896 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000897 {
898 params[i] = (float)intParams[i];
899 }
900 }
901 break;
902 default: UNREACHABLE();
903 }
904 }
905 }
906
907 return true;
908}
909
910bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
911{
912 if (location < 0 || location >= (int)mUniformIndex.size())
913 {
914 return false;
915 }
916
917 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
918
919 // sized queries -- ensure the provided buffer is large enough
920 if (bufSize)
921 {
922 int requiredBytes = UniformExternalSize(targetUniform->type);
923 if (*bufSize < requiredBytes)
924 {
925 return false;
926 }
927 }
928
929 switch (targetUniform->type)
930 {
931 case GL_FLOAT_MAT2:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000932 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000933 break;
934 case GL_FLOAT_MAT3:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000935 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000936 break;
937 case GL_FLOAT_MAT4:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000938 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000939 break;
940 default:
941 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000942 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000943
944 switch (UniformComponentType(targetUniform->type))
945 {
946 case GL_BOOL:
947 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000948 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000949
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000950 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000951 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000952 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000953 }
954 }
955 break;
956 case GL_FLOAT:
957 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000958 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000959
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000960 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000961 {
962 params[i] = (GLint)floatParams[i];
963 }
964 }
965 break;
966 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000967 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
968 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000969 break;
970 default: UNREACHABLE();
971 }
972 }
973 }
974
975 return true;
976}
977
978void ProgramBinary::dirtyAllUniforms()
979{
980 unsigned int numUniforms = mUniforms.size();
981 for (unsigned int index = 0; index < numUniforms; index++)
982 {
983 mUniforms[index]->dirty = true;
984 }
985}
986
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000987// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000988void ProgramBinary::applyUniforms()
989{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000990 // Retrieve sampler uniform values
991 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
992 {
993 Uniform *targetUniform = *ub;
994
995 if (targetUniform->dirty)
996 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000997 if (targetUniform->type == GL_SAMPLER_2D ||
998 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000999 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001000 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +00001001 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001002
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001003 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001004 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001005 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001006
1007 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001008 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001009 unsigned int samplerIndex = firstIndex + i;
1010
1011 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001012 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001013 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +00001014 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001015 }
1016 }
1017 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001018
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001019 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001020 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001021 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001022
1023 for (int i = 0; i < count; i++)
1024 {
1025 unsigned int samplerIndex = firstIndex + i;
1026
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001027 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001028 {
1029 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +00001030 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +00001031 }
1032 }
1033 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001034 }
1035 }
1036 }
1037
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +00001038 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001039}
1040
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001041// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1042// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001043int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001045 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001046
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001047 fragmentShader->resetVaryingsRegisterAssignment();
1048
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001049 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1050 {
1051 int n = VariableRowCount(varying->type) * varying->size;
1052 int m = VariableColumnCount(varying->type);
1053 bool success = false;
1054
1055 if (m == 2 || m == 3 || m == 4)
1056 {
1057 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1058 {
1059 bool available = true;
1060
1061 for (int y = 0; y < n && available; y++)
1062 {
1063 for (int x = 0; x < m && available; x++)
1064 {
1065 if (packing[r + y][x])
1066 {
1067 available = false;
1068 }
1069 }
1070 }
1071
1072 if (available)
1073 {
1074 varying->reg = r;
1075 varying->col = 0;
1076
1077 for (int y = 0; y < n; y++)
1078 {
1079 for (int x = 0; x < m; x++)
1080 {
1081 packing[r + y][x] = &*varying;
1082 }
1083 }
1084
1085 success = true;
1086 }
1087 }
1088
1089 if (!success && m == 2)
1090 {
1091 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1092 {
1093 bool available = true;
1094
1095 for (int y = 0; y < n && available; y++)
1096 {
1097 for (int x = 2; x < 4 && available; x++)
1098 {
1099 if (packing[r + y][x])
1100 {
1101 available = false;
1102 }
1103 }
1104 }
1105
1106 if (available)
1107 {
1108 varying->reg = r;
1109 varying->col = 2;
1110
1111 for (int y = 0; y < n; y++)
1112 {
1113 for (int x = 2; x < 4; x++)
1114 {
1115 packing[r + y][x] = &*varying;
1116 }
1117 }
1118
1119 success = true;
1120 }
1121 }
1122 }
1123 }
1124 else if (m == 1)
1125 {
1126 int space[4] = {0};
1127
1128 for (int y = 0; y < maxVaryingVectors; y++)
1129 {
1130 for (int x = 0; x < 4; x++)
1131 {
1132 space[x] += packing[y][x] ? 0 : 1;
1133 }
1134 }
1135
1136 int column = 0;
1137
1138 for (int x = 0; x < 4; x++)
1139 {
1140 if (space[x] >= n && space[x] < space[column])
1141 {
1142 column = x;
1143 }
1144 }
1145
1146 if (space[column] >= n)
1147 {
1148 for (int r = 0; r < maxVaryingVectors; r++)
1149 {
1150 if (!packing[r][column])
1151 {
1152 varying->reg = r;
1153
1154 for (int y = r; y < r + n; y++)
1155 {
1156 packing[y][column] = &*varying;
1157 }
1158
1159 break;
1160 }
1161 }
1162
1163 varying->col = column;
1164
1165 success = true;
1166 }
1167 }
1168 else UNREACHABLE();
1169
1170 if (!success)
1171 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001172 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001173
1174 return -1;
1175 }
1176 }
1177
1178 // Return the number of used registers
1179 int registers = 0;
1180
1181 for (int r = 0; r < maxVaryingVectors; r++)
1182 {
1183 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1184 {
1185 registers++;
1186 }
1187 }
1188
1189 return registers;
1190}
1191
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001192bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1193 std::string& pixelHLSL, std::string& vertexHLSL,
1194 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001195{
1196 if (pixelHLSL.empty() || vertexHLSL.empty())
1197 {
1198 return false;
1199 }
1200
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001201 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001202 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001203 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001204
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001205 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1206
1207 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001209 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001210
1211 return false;
1212 }
1213
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001214 vertexShader->resetVaryingsRegisterAssignment();
1215
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001216 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1217 {
1218 bool matched = false;
1219
1220 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1221 {
1222 if (output->name == input->name)
1223 {
1224 if (output->type != input->type || output->size != input->size)
1225 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001226 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 +00001227
1228 return false;
1229 }
1230
1231 output->reg = input->reg;
1232 output->col = input->col;
1233
1234 matched = true;
1235 break;
1236 }
1237 }
1238
1239 if (!matched)
1240 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001241 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 return false;
1244 }
1245 }
1246
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001247 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001248 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001249 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001250 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1251
1252 // special varyings that use reserved registers
1253 int reservedRegisterIndex = registers;
1254 std::string fragCoordSemantic;
1255 std::string pointCoordSemantic;
1256
1257 if (fragmentShader->mUsesFragCoord)
1258 {
1259 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1260 }
1261
1262 if (fragmentShader->mUsesPointCoord)
1263 {
1264 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1265 // In DX11 we compute this in the GS.
1266 if (shaderModel == 3)
1267 {
1268 pointCoordSemantic = "TEXCOORD0";
1269 }
1270 else if (shaderModel >= 4)
1271 {
1272 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1273 }
1274 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001275
1276 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001277 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278
1279 int semanticIndex = 0;
1280 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1281 {
1282 switch (attribute->type)
1283 {
1284 case GL_FLOAT: vertexHLSL += " float "; break;
1285 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1286 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1287 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1288 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1289 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1290 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1291 default: UNREACHABLE();
1292 }
1293
1294 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1295
1296 semanticIndex += VariableRowCount(attribute->type);
1297 }
1298
1299 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001300 "\n"
1301 "struct VS_OUTPUT\n"
1302 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001303
1304 for (int r = 0; r < registers; r++)
1305 {
1306 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1307
1308 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1309 }
1310
1311 if (fragmentShader->mUsesFragCoord)
1312 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001313 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314 }
1315
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001316 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001317 {
1318 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1319 }
1320
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001321 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"
1322 "};\n"
1323 "\n"
1324 "VS_OUTPUT main(VS_INPUT input)\n"
1325 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001326
1327 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1328 {
1329 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1330
1331 if (VariableRowCount(attribute->type) > 1) // Matrix
1332 {
1333 vertexHLSL += "transpose";
1334 }
1335
1336 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1337 }
1338
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001339 if (shaderModel >= 4)
1340 {
1341 vertexHLSL += "\n"
1342 " gl_main();\n"
1343 "\n"
1344 " VS_OUTPUT output;\n"
1345 " output.gl_Position.x = gl_Position.x;\n"
1346 " output.gl_Position.y = -gl_Position.y;\n"
1347 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1348 " output.gl_Position.w = gl_Position.w;\n";
1349 }
1350 else
1351 {
1352 vertexHLSL += "\n"
1353 " gl_main();\n"
1354 "\n"
1355 " VS_OUTPUT output;\n"
1356 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1357 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
1358 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1359 " output.gl_Position.w = gl_Position.w;\n";
1360 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001361
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001362 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001363 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001364 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001365 }
1366
1367 if (fragmentShader->mUsesFragCoord)
1368 {
1369 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1370 }
1371
1372 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1373 {
1374 if (varying->reg >= 0)
1375 {
1376 for (int i = 0; i < varying->size; i++)
1377 {
1378 int rows = VariableRowCount(varying->type);
1379
1380 for (int j = 0; j < rows; j++)
1381 {
1382 int r = varying->reg + i * rows + j;
1383 vertexHLSL += " output.v" + str(r);
1384
1385 bool sharedRegister = false; // Register used by multiple varyings
1386
1387 for (int x = 0; x < 4; x++)
1388 {
1389 if (packing[r][x] && packing[r][x] != packing[r][0])
1390 {
1391 sharedRegister = true;
1392 break;
1393 }
1394 }
1395
1396 if(sharedRegister)
1397 {
1398 vertexHLSL += ".";
1399
1400 for (int x = 0; x < 4; x++)
1401 {
1402 if (packing[r][x] == &*varying)
1403 {
1404 switch(x)
1405 {
1406 case 0: vertexHLSL += "x"; break;
1407 case 1: vertexHLSL += "y"; break;
1408 case 2: vertexHLSL += "z"; break;
1409 case 3: vertexHLSL += "w"; break;
1410 }
1411 }
1412 }
1413 }
1414
1415 vertexHLSL += " = " + varying->name;
1416
1417 if (varying->array)
1418 {
1419 vertexHLSL += "[" + str(i) + "]";
1420 }
1421
1422 if (rows > 1)
1423 {
1424 vertexHLSL += "[" + str(j) + "]";
1425 }
1426
1427 vertexHLSL += ";\n";
1428 }
1429 }
1430 }
1431 }
1432
1433 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001434 " return output;\n"
1435 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001436
1437 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001438 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001439
1440 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1441 {
1442 if (varying->reg >= 0)
1443 {
1444 for (int i = 0; i < varying->size; i++)
1445 {
1446 int rows = VariableRowCount(varying->type);
1447 for (int j = 0; j < rows; j++)
1448 {
1449 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001450 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451 }
1452 }
1453 }
1454 else UNREACHABLE();
1455 }
1456
1457 if (fragmentShader->mUsesFragCoord)
1458 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001459 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001460
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001461 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001462 {
1463 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1464 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001465 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001466 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1468 }
1469 }
1470
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001471 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001472 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001473 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001474 }
1475
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001476 pixelHLSL += "};\n"
1477 "\n"
1478 "struct PS_OUTPUT\n"
1479 "{\n"
1480 " float4 gl_Color[1] : " + targetSemantic + ";\n"
1481 "};\n"
1482 "\n";
1483
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001484 if (fragmentShader->mUsesFrontFacing)
1485 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001486 if (shaderModel >= 4)
1487 {
1488 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1489 "{\n";
1490 }
1491 else
1492 {
1493 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1494 "{\n";
1495 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001496 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001497 else
1498 {
1499 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1500 "{\n";
1501 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001502
1503 if (fragmentShader->mUsesFragCoord)
1504 {
1505 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1506
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001507 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001508 {
1509 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1510 " gl_FragCoord.y = input.dx_VPos.y;\n";
1511 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001512 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001513 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001514 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001515 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001516 }
1517 else
1518 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001519 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1520 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1521 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001522 }
1523
daniel@transgaming.com12985182012-12-20 20:56:31 +00001524 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001525 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001526 }
1527
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001528 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001529 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001530 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1531 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001532 }
1533
1534 if (fragmentShader->mUsesFrontFacing)
1535 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001536 if (shaderModel <= 3)
1537 {
1538 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1539 }
1540 else
1541 {
1542 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1543 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001544 }
1545
1546 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1547 {
1548 if (varying->reg >= 0)
1549 {
1550 for (int i = 0; i < varying->size; i++)
1551 {
1552 int rows = VariableRowCount(varying->type);
1553 for (int j = 0; j < rows; j++)
1554 {
1555 std::string n = str(varying->reg + i * rows + j);
1556 pixelHLSL += " " + varying->name;
1557
1558 if (varying->array)
1559 {
1560 pixelHLSL += "[" + str(i) + "]";
1561 }
1562
1563 if (rows > 1)
1564 {
1565 pixelHLSL += "[" + str(j) + "]";
1566 }
1567
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001568 switch (VariableColumnCount(varying->type))
1569 {
1570 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1571 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1572 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1573 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1574 default: UNREACHABLE();
1575 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001576 }
1577 }
1578 }
1579 else UNREACHABLE();
1580 }
1581
1582 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001583 " gl_main();\n"
1584 "\n"
1585 " PS_OUTPUT output;\n"
1586 " output.gl_Color[0] = gl_Color[0];\n"
1587 "\n"
1588 " return output;\n"
1589 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001590
1591 return true;
1592}
1593
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001594bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1595{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001596 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001597
1598 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600 if (format != GL_PROGRAM_BINARY_ANGLE)
1601 {
1602 infoLog.append("Invalid program binary format.");
1603 return false;
1604 }
1605
1606 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001607 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001608 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001609 {
1610 infoLog.append("Invalid program binary version.");
1611 return false;
1612 }
1613
1614 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1615 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001616 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001618 stream.read(&name);
1619 mLinkedAttribute[i].name = name;
1620 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621 }
1622
1623 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1624 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001625 stream.read(&mSamplersPS[i].active);
1626 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627
1628 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001629 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001630 mSamplersPS[i].textureType = (TextureType) textureType;
1631 }
1632
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001633 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 stream.read(&mSamplersVS[i].active);
1636 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001637
1638 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001639 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640 mSamplersVS[i].textureType = (TextureType) textureType;
1641 }
1642
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001643 stream.read(&mUsedVertexSamplerRange);
1644 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001645 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646
1647 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001648 stream.read(&size);
1649 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001650 {
1651 infoLog.append("Invalid program binary.");
1652 return false;
1653 }
1654
1655 mUniforms.resize(size);
1656 for (unsigned int i = 0; i < size; ++i)
1657 {
1658 GLenum type;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001659 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 unsigned int arraySize;
1661
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001662 stream.read(&type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001663 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001666 mUniforms[i] = new Uniform(type, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001668 stream.read(&mUniforms[i]->psRegisterIndex);
1669 stream.read(&mUniforms[i]->vsRegisterIndex);
1670 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 }
1672
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&size);
1674 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 {
1676 infoLog.append("Invalid program binary.");
1677 return false;
1678 }
1679
1680 mUniformIndex.resize(size);
1681 for (unsigned int i = 0; i < size; ++i)
1682 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001683 stream.read(&mUniformIndex[i].name);
1684 stream.read(&mUniformIndex[i].element);
1685 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001686 }
1687
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001689 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001690
1691 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001692 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001694 unsigned int geometryShaderSize;
1695 stream.read(&geometryShaderSize);
1696
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001697 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001698
daniel@transgaming.com36038542012-11-28 20:59:26 +00001699 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001700 ptr += sizeof(GUID);
1701
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001702 GUID identifier = mRenderer->getAdapterIdentifier();
1703 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704 {
1705 infoLog.append("Invalid program binary.");
1706 return false;
1707 }
1708
1709 const char *pixelShaderFunction = ptr;
1710 ptr += pixelShaderSize;
1711
1712 const char *vertexShaderFunction = ptr;
1713 ptr += vertexShaderSize;
1714
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001715 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1716 ptr += geometryShaderSize;
1717
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001718 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001719 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001720 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001721 {
1722 infoLog.append("Could not create pixel shader.");
1723 return false;
1724 }
1725
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001726 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001727 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001728 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 {
1730 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001731 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001732 mPixelExecutable = NULL;
1733 return false;
1734 }
1735
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001736 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1737 {
1738 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1739 geometryShaderSize, rx::SHADER_GEOMETRY);
1740 if (!mGeometryExecutable)
1741 {
1742 infoLog.append("Could not create geometry shader.");
1743 delete mPixelExecutable;
1744 mPixelExecutable = NULL;
1745 delete mVertexExecutable;
1746 mVertexExecutable = NULL;
1747 return false;
1748 }
1749 }
1750 else
1751 {
1752 mGeometryExecutable = NULL;
1753 }
1754
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001755 return true;
1756}
1757
1758bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1759{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001760 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001761
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001762 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001763 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764
1765 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1766 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.write(mLinkedAttribute[i].type);
1768 stream.write(mLinkedAttribute[i].name);
1769 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001770 }
1771
1772 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1773 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001774 stream.write(mSamplersPS[i].active);
1775 stream.write(mSamplersPS[i].logicalTextureUnit);
1776 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777 }
1778
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001779 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(mSamplersVS[i].active);
1782 stream.write(mSamplersVS[i].logicalTextureUnit);
1783 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001784 }
1785
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001786 stream.write(mUsedVertexSamplerRange);
1787 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001788 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001789
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001790 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1792 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001793 stream.write(mUniforms[i]->type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001794 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001795 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001797 stream.write(mUniforms[i]->psRegisterIndex);
1798 stream.write(mUniforms[i]->vsRegisterIndex);
1799 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001800 }
1801
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001802 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001803 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1804 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001805 stream.write(mUniformIndex[i].name);
1806 stream.write(mUniformIndex[i].element);
1807 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 }
1809
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001810 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001811 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001813 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001814 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001815
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001816 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1817 stream.write(geometryShaderSize);
1818
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001819 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001821 GLsizei streamLength = stream.length();
1822 const void *streamData = stream.data();
1823
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001824 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825 if (totalLength > bufSize)
1826 {
1827 if (length)
1828 {
1829 *length = 0;
1830 }
1831
1832 return false;
1833 }
1834
1835 if (binary)
1836 {
1837 char *ptr = (char*) binary;
1838
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001839 memcpy(ptr, streamData, streamLength);
1840 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001841
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001842 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001843 ptr += sizeof(GUID);
1844
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001845 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001846 ptr += pixelShaderSize;
1847
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001848 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001849 ptr += vertexShaderSize;
1850
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001851 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1852 {
1853 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1854 ptr += geometryShaderSize;
1855 }
1856
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857 ASSERT(ptr - totalLength == binary);
1858 }
1859
1860 if (length)
1861 {
1862 *length = totalLength;
1863 }
1864
1865 return true;
1866}
1867
1868GLint ProgramBinary::getLength()
1869{
1870 GLint length;
1871 if (save(NULL, INT_MAX, &length))
1872 {
1873 return length;
1874 }
1875 else
1876 {
1877 return 0;
1878 }
1879}
1880
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001881bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001882{
1883 if (!fragmentShader || !fragmentShader->isCompiled())
1884 {
1885 return false;
1886 }
1887
1888 if (!vertexShader || !vertexShader->isCompiled())
1889 {
1890 return false;
1891 }
1892
1893 std::string pixelHLSL = fragmentShader->getHLSL();
1894 std::string vertexHLSL = vertexShader->getHLSL();
1895
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001896 // Map the varyings to the register file
1897 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1898 int registers = packVaryings(infoLog, packing, fragmentShader);
1899
1900 if (registers < 0)
1901 {
1902 return false;
1903 }
1904
1905 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001906 {
1907 return false;
1908 }
1909
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001910 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001911 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1912 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001913
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001914 if (usesGeometryShader())
1915 {
1916 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1917 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1918 }
1919
1920 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001921 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001922 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001923 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001924
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001925 delete mVertexExecutable;
1926 mVertexExecutable = NULL;
1927 delete mPixelExecutable;
1928 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001929 delete mGeometryExecutable;
1930 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001931 }
1932
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001933 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1934 {
1935 success = false;
1936 }
1937
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001938 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001939 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001940 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001941 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001942
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001943 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001944}
1945
1946// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001947bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001948{
1949 unsigned int usedLocations = 0;
1950
1951 // Link attributes that have a binding location
1952 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1953 {
1954 int location = attributeBindings.getAttributeBinding(attribute->name);
1955
1956 if (location != -1) // Set by glBindAttribLocation
1957 {
1958 if (!mLinkedAttribute[location].name.empty())
1959 {
1960 // Multiple active attributes bound to the same location; not an error
1961 }
1962
1963 mLinkedAttribute[location] = *attribute;
1964
1965 int rows = VariableRowCount(attribute->type);
1966
1967 if (rows + location > MAX_VERTEX_ATTRIBS)
1968 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001969 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 +00001970
1971 return false;
1972 }
1973
1974 for (int i = 0; i < rows; i++)
1975 {
1976 usedLocations |= 1 << (location + i);
1977 }
1978 }
1979 }
1980
1981 // Link attributes that don't have a binding location
1982 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1983 {
1984 int location = attributeBindings.getAttributeBinding(attribute->name);
1985
1986 if (location == -1) // Not set by glBindAttribLocation
1987 {
1988 int rows = VariableRowCount(attribute->type);
1989 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1990
1991 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1992 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001993 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001994
1995 return false; // Fail to link
1996 }
1997
1998 mLinkedAttribute[availableIndex] = *attribute;
1999 }
2000 }
2001
2002 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2003 {
2004 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2005 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2006
2007 for (int r = 0; r < rows; r++)
2008 {
2009 mSemanticIndex[attributeIndex++] = index++;
2010 }
2011 }
2012
2013 return true;
2014}
2015
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002016bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002017{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002018 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002019 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002020 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002021 {
2022 return false;
2023 }
2024 }
2025
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002026 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002027 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002028 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002029 {
2030 return false;
2031 }
2032 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002033
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002034 return true;
2035}
2036
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002037bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002038{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002039 if (constant.type == GL_SAMPLER_2D ||
2040 constant.type == GL_SAMPLER_CUBE)
2041 {
2042 unsigned int samplerIndex = constant.registerIndex;
2043
2044 do
2045 {
2046 if (shader == GL_VERTEX_SHADER)
2047 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002048 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002049 {
2050 mSamplersVS[samplerIndex].active = true;
2051 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2052 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2053 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2054 }
2055 else
2056 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002057 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002058 return false;
2059 }
2060 }
2061 else if (shader == GL_FRAGMENT_SHADER)
2062 {
2063 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2064 {
2065 mSamplersPS[samplerIndex].active = true;
2066 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2067 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2068 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2069 }
2070 else
2071 {
2072 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2073 return false;
2074 }
2075 }
2076 else UNREACHABLE();
2077
2078 samplerIndex++;
2079 }
2080 while (samplerIndex < constant.registerIndex + constant.arraySize);
2081 }
2082
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002083 Uniform *uniform = NULL;
2084 GLint location = getUniformLocation(constant.name);
2085
2086 if (location >= 0) // Previously defined, types must match
2087 {
2088 uniform = mUniforms[mUniformIndex[location].index];
2089
2090 if (uniform->type != constant.type)
2091 {
2092 return false;
2093 }
2094 }
2095 else
2096 {
2097 uniform = new Uniform(constant.type, constant.name, constant.arraySize);
2098 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002099
2100 if (!uniform)
2101 {
2102 return false;
2103 }
2104
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002105 if (shader == GL_FRAGMENT_SHADER)
2106 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002107 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002108 }
2109 else if (shader == GL_VERTEX_SHADER)
2110 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002111 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002112 }
2113 else UNREACHABLE();
2114
2115 if (location >= 0)
2116 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002117 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002118 }
2119
2120 mUniforms.push_back(uniform);
2121 unsigned int uniformIndex = mUniforms.size() - 1;
2122
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002123 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002124 {
2125 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2126 }
2127
2128 return true;
2129}
2130
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002131std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2132{
2133 // for now we only handle point sprite emulation
2134 ASSERT(usesPointSpriteEmulation());
2135 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2136}
2137
2138std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2139{
2140 ASSERT(registers >= 0);
2141 ASSERT(vertexShader->mUsesPointSize);
2142 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2143
2144 std::string geomHLSL;
2145
2146 std::string varyingSemantic = "TEXCOORD";
2147
2148 std::string fragCoordSemantic;
2149 std::string pointCoordSemantic;
2150
2151 int reservedRegisterIndex = registers;
2152
2153 if (fragmentShader->mUsesFragCoord)
2154 {
2155 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2156 }
2157
2158 if (fragmentShader->mUsesPointCoord)
2159 {
2160 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2161 }
2162
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002163 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2164 "\n"
2165 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002166 "{\n";
2167
2168 for (int r = 0; r < registers; r++)
2169 {
2170 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2171
2172 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2173 }
2174
2175 if (fragmentShader->mUsesFragCoord)
2176 {
2177 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2178 }
2179
2180 geomHLSL += " float gl_PointSize : PSIZE;\n"
2181 " float4 gl_Position : SV_Position;\n"
2182 "};\n"
2183 "\n"
2184 "struct GS_OUTPUT\n"
2185 "{\n";
2186
2187 for (int r = 0; r < registers; r++)
2188 {
2189 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2190
2191 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2192 }
2193
2194 if (fragmentShader->mUsesFragCoord)
2195 {
2196 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2197 }
2198
2199 if (fragmentShader->mUsesPointCoord)
2200 {
2201 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2202 }
2203
2204 geomHLSL += " float4 gl_Position : SV_Position;\n"
2205 "};\n"
2206 "\n"
2207 "static float2 pointSpriteCorners[] = \n"
2208 "{\n"
2209 " float2( 0.5f, -0.5f),\n"
2210 " float2( 0.5f, 0.5f),\n"
2211 " float2(-0.5f, -0.5f),\n"
2212 " float2(-0.5f, 0.5f)\n"
2213 "};\n"
2214 "\n"
2215 "static float2 pointSpriteTexcoords[] = \n"
2216 "{\n"
2217 " float2(1.0f, 1.0f),\n"
2218 " float2(1.0f, 0.0f),\n"
2219 " float2(0.0f, 1.0f),\n"
2220 " float2(0.0f, 0.0f)\n"
2221 "};\n"
2222 "\n"
2223 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2224 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2225 "\n"
2226 "[maxvertexcount(4)]\n"
2227 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2228 "{\n"
2229 " GS_OUTPUT output = (GS_OUTPUT)0;\n";
2230
2231 for (int r = 0; r < registers; r++)
2232 {
2233 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2234 }
2235
2236 if (fragmentShader->mUsesFragCoord)
2237 {
2238 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2239 }
2240
2241 geomHLSL += " \n"
2242 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2243 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002244 " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y);\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002245
2246 for (int corner = 0; corner < 4; corner++)
2247 {
2248 geomHLSL += " \n"
2249 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2250
2251 if (fragmentShader->mUsesPointCoord)
2252 {
2253 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2254 }
2255
2256 geomHLSL += " outStream.Append(output);\n";
2257 }
2258
2259 geomHLSL += " \n"
2260 " outStream.RestartStrip();\n"
2261 "}\n";
2262
2263 return geomHLSL;
2264}
2265
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002266// This method needs to match OutputHLSL::decorate
2267std::string ProgramBinary::decorateAttribute(const std::string &name)
2268{
2269 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2270 {
2271 return "_" + name;
2272 }
2273
2274 return name;
2275}
2276
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002277bool ProgramBinary::isValidated() const
2278{
2279 return mValidated;
2280}
2281
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002282void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2283{
2284 // Skip over inactive attributes
2285 unsigned int activeAttribute = 0;
2286 unsigned int attribute;
2287 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2288 {
2289 if (mLinkedAttribute[attribute].name.empty())
2290 {
2291 continue;
2292 }
2293
2294 if (activeAttribute == index)
2295 {
2296 break;
2297 }
2298
2299 activeAttribute++;
2300 }
2301
2302 if (bufsize > 0)
2303 {
2304 const char *string = mLinkedAttribute[attribute].name.c_str();
2305
2306 strncpy(name, string, bufsize);
2307 name[bufsize - 1] = '\0';
2308
2309 if (length)
2310 {
2311 *length = strlen(name);
2312 }
2313 }
2314
2315 *size = 1; // Always a single 'type' instance
2316
2317 *type = mLinkedAttribute[attribute].type;
2318}
2319
2320GLint ProgramBinary::getActiveAttributeCount()
2321{
2322 int count = 0;
2323
2324 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2325 {
2326 if (!mLinkedAttribute[attributeIndex].name.empty())
2327 {
2328 count++;
2329 }
2330 }
2331
2332 return count;
2333}
2334
2335GLint ProgramBinary::getActiveAttributeMaxLength()
2336{
2337 int maxLength = 0;
2338
2339 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2340 {
2341 if (!mLinkedAttribute[attributeIndex].name.empty())
2342 {
2343 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2344 }
2345 }
2346
2347 return maxLength;
2348}
2349
2350void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2351{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002352 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002353
2354 if (bufsize > 0)
2355 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002356 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002357
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002358 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002359 {
2360 string += "[0]";
2361 }
2362
2363 strncpy(name, string.c_str(), bufsize);
2364 name[bufsize - 1] = '\0';
2365
2366 if (length)
2367 {
2368 *length = strlen(name);
2369 }
2370 }
2371
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002372 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002373
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002374 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002375}
2376
2377GLint ProgramBinary::getActiveUniformCount()
2378{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002379 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002380}
2381
2382GLint ProgramBinary::getActiveUniformMaxLength()
2383{
2384 int maxLength = 0;
2385
2386 unsigned int numUniforms = mUniforms.size();
2387 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2388 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002389 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002390 {
2391 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2392 if (mUniforms[uniformIndex]->isArray())
2393 {
2394 length += 3; // Counting in "[0]".
2395 }
2396 maxLength = std::max(length, maxLength);
2397 }
2398 }
2399
2400 return maxLength;
2401}
2402
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002403void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002404{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002405 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002406 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002407 {
2408 mValidated = false;
2409 }
2410 else
2411 {
2412 mValidated = true;
2413 }
2414}
2415
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002416bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002417{
2418 // if any two active samplers in a program are of different types, but refer to the same
2419 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2420 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2421
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002422 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002423 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002424
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002425 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002426 {
2427 textureUnitType[i] = TEXTURE_UNKNOWN;
2428 }
2429
2430 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2431 {
2432 if (mSamplersPS[i].active)
2433 {
2434 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2435
2436 if (unit >= maxCombinedTextureImageUnits)
2437 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002438 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002439 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002440 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002441 }
2442
2443 return false;
2444 }
2445
2446 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2447 {
2448 if (mSamplersPS[i].textureType != textureUnitType[unit])
2449 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002450 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002451 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002452 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002453 }
2454
2455 return false;
2456 }
2457 }
2458 else
2459 {
2460 textureUnitType[unit] = mSamplersPS[i].textureType;
2461 }
2462 }
2463 }
2464
2465 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2466 {
2467 if (mSamplersVS[i].active)
2468 {
2469 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2470
2471 if (unit >= maxCombinedTextureImageUnits)
2472 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002473 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002474 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002475 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002476 }
2477
2478 return false;
2479 }
2480
2481 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2482 {
2483 if (mSamplersVS[i].textureType != textureUnitType[unit])
2484 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002485 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002486 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002487 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002488 }
2489
2490 return false;
2491 }
2492 }
2493 else
2494 {
2495 textureUnitType[unit] = mSamplersVS[i].textureType;
2496 }
2497 }
2498 }
2499
2500 return true;
2501}
2502
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002503ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2504{
2505}
2506
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002507}