blob: 21c778f0d12f4b073d6bf528dd0b80959b7b88fc [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000025
daniel@transgaming.com88853c52012-12-20 20:56:40 +000026#undef near
27#undef far
28
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029namespace gl
30{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031std::string str(int i)
32{
33 char buffer[20];
34 snprintf(buffer, sizeof(buffer), "%d", i);
35 return buffer;
36}
37
daniel@transgaming.comdb019952012-12-20 21:13:32 +000038UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
39 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000040{
41}
42
daniel@transgaming.come87ca002012-07-24 18:30:43 +000043unsigned int ProgramBinary::mCurrentSerial = 1;
44
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000045ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000047 mPixelExecutable = NULL;
48 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000049 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000050
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000051 mValidated = false;
52
53 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
54 {
55 mSemanticIndex[index] = -1;
56 }
57
58 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
59 {
60 mSamplersPS[index].active = false;
61 }
62
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000063 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000064 {
65 mSamplersVS[index].active = false;
66 }
67
68 mUsedVertexSamplerRange = 0;
69 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000070 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071}
72
73ProgramBinary::~ProgramBinary()
74{
daniel@transgaming.com95892412012-11-28 20:59:09 +000075 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000076 mPixelExecutable = NULL;
77
daniel@transgaming.com95892412012-11-28 20:59:09 +000078 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000079 mVertexExecutable = NULL;
80
81 delete mGeometryExecutable;
82 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000084 while (!mUniforms.empty())
85 {
86 delete mUniforms.back();
87 mUniforms.pop_back();
88 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000089}
90
daniel@transgaming.come87ca002012-07-24 18:30:43 +000091unsigned int ProgramBinary::getSerial() const
92{
93 return mSerial;
94}
95
96unsigned int ProgramBinary::issueSerial()
97{
98 return mCurrentSerial++;
99}
100
daniel@transgaming.com95892412012-11-28 20:59:09 +0000101rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102{
103 return mPixelExecutable;
104}
105
daniel@transgaming.com95892412012-11-28 20:59:09 +0000106rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000107{
108 return mVertexExecutable;
109}
110
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000111rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
112{
113 return mGeometryExecutable;
114}
115
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116GLuint ProgramBinary::getAttributeLocation(const char *name)
117{
118 if (name)
119 {
120 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
121 {
122 if (mLinkedAttribute[index].name == std::string(name))
123 {
124 return index;
125 }
126 }
127 }
128
129 return -1;
130}
131
132int ProgramBinary::getSemanticIndex(int attributeIndex)
133{
134 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
135
136 return mSemanticIndex[attributeIndex];
137}
138
139// Returns one more than the highest sampler index used.
140GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
141{
142 switch (type)
143 {
144 case SAMPLER_PIXEL:
145 return mUsedPixelSamplerRange;
146 case SAMPLER_VERTEX:
147 return mUsedVertexSamplerRange;
148 default:
149 UNREACHABLE();
150 return 0;
151 }
152}
153
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000154bool ProgramBinary::usesPointSize() const
155{
156 return mUsesPointSize;
157}
158
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000159bool ProgramBinary::usesPointSpriteEmulation() const
160{
161 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
162}
163
164bool ProgramBinary::usesGeometryShader() const
165{
166 return usesPointSpriteEmulation();
167}
168
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000169// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
170// index (0-15 for the pixel shader and 0-3 for the vertex shader).
171GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
172{
173 GLint logicalTextureUnit = -1;
174
175 switch (type)
176 {
177 case SAMPLER_PIXEL:
178 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
179
180 if (mSamplersPS[samplerIndex].active)
181 {
182 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
183 }
184 break;
185 case SAMPLER_VERTEX:
186 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
187
188 if (mSamplersVS[samplerIndex].active)
189 {
190 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
191 }
192 break;
193 default: UNREACHABLE();
194 }
195
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000196 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000197 {
198 return logicalTextureUnit;
199 }
200
201 return -1;
202}
203
204// Returns the texture type for a given Direct3D 9 sampler type and
205// index (0-15 for the pixel shader and 0-3 for the vertex shader).
206TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
207{
208 switch (type)
209 {
210 case SAMPLER_PIXEL:
211 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
212 ASSERT(mSamplersPS[samplerIndex].active);
213 return mSamplersPS[samplerIndex].textureType;
214 case SAMPLER_VERTEX:
215 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
216 ASSERT(mSamplersVS[samplerIndex].active);
217 return mSamplersVS[samplerIndex].textureType;
218 default: UNREACHABLE();
219 }
220
221 return TEXTURE_2D;
222}
223
224GLint ProgramBinary::getUniformLocation(std::string name)
225{
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000226 unsigned int subscript = GL_INVALID_INDEX;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000227
228 // Strip any trailing array operator and retrieve the subscript
229 size_t open = name.find_last_of('[');
230 size_t close = name.find_last_of(']');
231 if (open != std::string::npos && close == name.length() - 1)
232 {
233 subscript = atoi(name.substr(open + 1).c_str());
234 name.erase(open);
235 }
236
237 unsigned int numUniforms = mUniformIndex.size();
238 for (unsigned int location = 0; location < numUniforms; location++)
239 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000240 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000241 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000242 const int index = mUniformIndex[location].index;
243 const bool isArray = mUniforms[index]->isArray();
244
245 if ((isArray && mUniformIndex[location].element == subscript) ||
246 (subscript == GL_INVALID_INDEX))
247 {
248 return location;
249 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000250 }
251 }
252
253 return -1;
254}
255
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000256GLuint ProgramBinary::getUniformIndex(std::string name)
257{
258 unsigned int subscript = GL_INVALID_INDEX;
259
260 // Strip any trailing array operator and retrieve the subscript
261 size_t open = name.find_last_of('[');
262 size_t close = name.find_last_of(']');
263 if (open != std::string::npos && close == name.length() - 1)
264 {
265 subscript = atoi(name.substr(open + 1).c_str());
266 name.erase(open);
267 }
268
269 // The app is not allowed to specify array indices other than 0 for arrays of basic types
270 if (subscript != 0 && subscript != GL_INVALID_INDEX)
271 {
272 return GL_INVALID_INDEX;
273 }
274
275 unsigned int numUniforms = mUniforms.size();
276 for (unsigned int index = 0; index < numUniforms; index++)
277 {
278 if (mUniforms[index]->name == name)
279 {
280 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
281 {
282 return index;
283 }
284 }
285 }
286
287 return GL_INVALID_INDEX;
288}
289
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000290template <typename T>
291bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000292{
293 if (location < 0 || location >= (int)mUniformIndex.size())
294 {
295 return false;
296 }
297
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000298 const int components = UniformComponentCount(targetUniformType);
299 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
300
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000301 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
302 targetUniform->dirty = true;
303
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000304 int elementCount = targetUniform->elementCount();
305
306 if (elementCount == 1 && count > 1)
307 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
308
309 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
310
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000311 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000312 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000313 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000314
315 for (int i = 0; i < count; i++)
316 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000317 for (int c = 0; c < components; c++)
318 {
319 target[c] = v[c];
320 }
321 for (int c = components; c < 4; c++)
322 {
323 target[c] = 0;
324 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000325 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000326 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000327 }
328 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000329 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000330 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000331 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000332
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000333 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000334 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000335 for (int c = 0; c < components; c++)
336 {
337 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
338 }
339 for (int c = components; c < 4; c++)
340 {
341 boolParams[c] = GL_FALSE;
342 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000343 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000344 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000345 }
346 }
347 else
348 {
349 return false;
350 }
351
352 return true;
353}
354
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000355bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
356{
357 return setUniform(location, count, v, GL_FLOAT);
358}
359
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000360bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
361{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000362 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000363}
364
365bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
366{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000367 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000368}
369
370bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
371{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000372 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000373}
374
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000375template<typename T>
376void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377{
378 int copyWidth = std::min(targetWidth, srcWidth);
379 int copyHeight = std::min(targetHeight, srcHeight);
380
381 for (int x = 0; x < copyWidth; x++)
382 {
383 for (int y = 0; y < copyHeight; y++)
384 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000385 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000386 }
387 }
388 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000389 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000390 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000391 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000393 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394 }
395 }
396 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000397 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398 {
399 for (int x = 0; x < targetWidth; x++)
400 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000401 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000402 }
403 }
404}
405
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000406template<typename T>
407void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
408{
409 int copyWidth = std::min(targetWidth, srcWidth);
410 int copyHeight = std::min(targetHeight, srcHeight);
411
412 for (int y = 0; y < copyHeight; y++)
413 {
414 for (int x = 0; x < copyWidth; x++)
415 {
416 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
417 }
418 }
419 // clear unfilled right side
420 for (int y = 0; y < copyHeight; y++)
421 {
422 for (int x = copyWidth; x < targetWidth; x++)
423 {
424 target[y * targetWidth + x] = static_cast<T>(0);
425 }
426 }
427 // clear unfilled bottom.
428 for (int y = copyHeight; y < targetHeight; y++)
429 {
430 for (int x = 0; x < targetWidth; x++)
431 {
432 target[y * targetWidth + x] = static_cast<T>(0);
433 }
434 }
435}
436
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000437template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000438bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439{
440 if (location < 0 || location >= (int)mUniformIndex.size())
441 {
442 return false;
443 }
444
445 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
446 targetUniform->dirty = true;
447
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000448 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000449 {
450 return false;
451 }
452
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000453 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000454
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000455 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000456 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
457
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000458 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000459 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4 * rows);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000460
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000461 for (int i = 0; i < count; i++)
462 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000463 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
464 if (transpose == GL_FALSE)
465 {
466 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
467 }
468 else
469 {
470 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
471 }
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000472 target += 4 * rows;
473 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000474 }
475
476 return true;
477}
478
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000479bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000480{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000481 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000482}
483
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000484bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000485{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000486 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000487}
488
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000489bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000490{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000491 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000492}
493
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000494bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000495{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000496 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000497}
498
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000499bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000500{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000501 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000502}
503
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000504bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000505{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000506 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000507}
508
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000509bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000510{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000511 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000512}
513
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000514bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000515{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000516 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000517}
518
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000519bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000520{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000521 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000522}
523
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
525{
526 if (location < 0 || location >= (int)mUniformIndex.size())
527 {
528 return false;
529 }
530
531 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
532 targetUniform->dirty = true;
533
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000534 int elementCount = targetUniform->elementCount();
535
536 if (elementCount == 1 && count > 1)
537 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
538
539 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
540
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000541 if (targetUniform->type == GL_INT ||
542 targetUniform->type == GL_SAMPLER_2D ||
543 targetUniform->type == GL_SAMPLER_CUBE)
544 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000545 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000546
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000547 for (int i = 0; i < count; i++)
548 {
549 target[0] = v[0];
550 target[1] = 0;
551 target[2] = 0;
552 target[3] = 0;
553 target += 4;
554 v += 1;
555 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000556 }
557 else if (targetUniform->type == GL_BOOL)
558 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000559 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000561 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000563 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
564 boolParams[1] = GL_FALSE;
565 boolParams[2] = GL_FALSE;
566 boolParams[3] = GL_FALSE;
567 boolParams += 4;
568 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000569 }
570 }
571 else
572 {
573 return false;
574 }
575
576 return true;
577}
578
579bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
580{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000581 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000582}
583
584bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
585{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000586 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000587}
588
589bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
590{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000591 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000592}
593
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000594bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
595{
596 return setUniform(location, count, v, GL_UNSIGNED_INT);
597}
598
599bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
600{
601 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
602}
603
604bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
605{
606 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
607}
608
609bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
610{
611 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
612}
613
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000614template <typename T>
615bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000616{
617 if (location < 0 || location >= (int)mUniformIndex.size())
618 {
619 return false;
620 }
621
622 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
623
624 // sized queries -- ensure the provided buffer is large enough
625 if (bufSize)
626 {
627 int requiredBytes = UniformExternalSize(targetUniform->type);
628 if (*bufSize < requiredBytes)
629 {
630 return false;
631 }
632 }
633
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000634 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000635 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000636 const int rows = VariableRowCount(targetUniform->type);
637 const int cols = VariableColumnCount(targetUniform->type);
638 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
639 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000640 else if (uniformType == UniformComponentType(targetUniform->type))
641 {
642 unsigned int size = UniformComponentCount(targetUniform->type);
643 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
644 size * sizeof(T));
645 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000646 else
647 {
648 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000649 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000650 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000651 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000652 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000653 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000655 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000656 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000657 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000658 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000659 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000660 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000661
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000662 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000663 {
664 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
665
666 for (unsigned int i = 0; i < size; i++)
667 {
668 params[i] = static_cast<T>(floatParams[i]);
669 }
670 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000671 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000672
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000673 case GL_INT:
674 {
675 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
676
677 for (unsigned int i = 0; i < size; i++)
678 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000679 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000680 }
681 }
682 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000683
684 case GL_UNSIGNED_INT:
685 {
686 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000687
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000688 for (unsigned int i = 0; i < size; i++)
689 {
690 params[i] = static_cast<T>(uintParams[i]);
691 }
692 }
693 break;
694
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000695 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696 }
697 }
698
699 return true;
700}
701
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000702bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
703{
704 return getUniformv(location, bufSize, params, GL_FLOAT);
705}
706
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000707bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
708{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000709 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000710}
711
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000712bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
713{
714 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
715}
716
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000717void ProgramBinary::dirtyAllUniforms()
718{
719 unsigned int numUniforms = mUniforms.size();
720 for (unsigned int index = 0; index < numUniforms; index++)
721 {
722 mUniforms[index]->dirty = true;
723 }
724}
725
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000726// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000727void ProgramBinary::applyUniforms()
728{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000729 // Retrieve sampler uniform values
730 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
731 {
732 Uniform *targetUniform = *ub;
733
734 if (targetUniform->dirty)
735 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000736 if (targetUniform->type == GL_SAMPLER_2D ||
737 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000738 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000739 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000740 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000741
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000742 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000743 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000744 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000745
746 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000747 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000748 unsigned int samplerIndex = firstIndex + i;
749
750 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000751 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000752 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000753 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000754 }
755 }
756 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000757
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000758 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000759 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000760 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000761
762 for (int i = 0; i < count; i++)
763 {
764 unsigned int samplerIndex = firstIndex + i;
765
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000766 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000767 {
768 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000769 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000770 }
771 }
772 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000773 }
774 }
775 }
776
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000777 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000778}
779
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000780// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
781// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000782int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000783{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000784 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000785
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000786 fragmentShader->resetVaryingsRegisterAssignment();
787
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000788 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
789 {
790 int n = VariableRowCount(varying->type) * varying->size;
791 int m = VariableColumnCount(varying->type);
792 bool success = false;
793
794 if (m == 2 || m == 3 || m == 4)
795 {
796 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
797 {
798 bool available = true;
799
800 for (int y = 0; y < n && available; y++)
801 {
802 for (int x = 0; x < m && available; x++)
803 {
804 if (packing[r + y][x])
805 {
806 available = false;
807 }
808 }
809 }
810
811 if (available)
812 {
813 varying->reg = r;
814 varying->col = 0;
815
816 for (int y = 0; y < n; y++)
817 {
818 for (int x = 0; x < m; x++)
819 {
820 packing[r + y][x] = &*varying;
821 }
822 }
823
824 success = true;
825 }
826 }
827
828 if (!success && m == 2)
829 {
830 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
831 {
832 bool available = true;
833
834 for (int y = 0; y < n && available; y++)
835 {
836 for (int x = 2; x < 4 && available; x++)
837 {
838 if (packing[r + y][x])
839 {
840 available = false;
841 }
842 }
843 }
844
845 if (available)
846 {
847 varying->reg = r;
848 varying->col = 2;
849
850 for (int y = 0; y < n; y++)
851 {
852 for (int x = 2; x < 4; x++)
853 {
854 packing[r + y][x] = &*varying;
855 }
856 }
857
858 success = true;
859 }
860 }
861 }
862 }
863 else if (m == 1)
864 {
865 int space[4] = {0};
866
867 for (int y = 0; y < maxVaryingVectors; y++)
868 {
869 for (int x = 0; x < 4; x++)
870 {
871 space[x] += packing[y][x] ? 0 : 1;
872 }
873 }
874
875 int column = 0;
876
877 for (int x = 0; x < 4; x++)
878 {
879 if (space[x] >= n && space[x] < space[column])
880 {
881 column = x;
882 }
883 }
884
885 if (space[column] >= n)
886 {
887 for (int r = 0; r < maxVaryingVectors; r++)
888 {
889 if (!packing[r][column])
890 {
891 varying->reg = r;
892
893 for (int y = r; y < r + n; y++)
894 {
895 packing[y][column] = &*varying;
896 }
897
898 break;
899 }
900 }
901
902 varying->col = column;
903
904 success = true;
905 }
906 }
907 else UNREACHABLE();
908
909 if (!success)
910 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000911 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000912
913 return -1;
914 }
915 }
916
917 // Return the number of used registers
918 int registers = 0;
919
920 for (int r = 0; r < maxVaryingVectors; r++)
921 {
922 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
923 {
924 registers++;
925 }
926 }
927
928 return registers;
929}
930
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000931bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
932 std::string& pixelHLSL, std::string& vertexHLSL,
933 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000934{
935 if (pixelHLSL.empty() || vertexHLSL.empty())
936 {
937 return false;
938 }
939
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000940 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
941 bool usesFragColor = fragmentShader->mUsesFragColor;
942 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +0000943 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000944 {
945 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
946 return false;
947 }
948
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000949 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +0000950 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000951 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000952
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000953 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
954
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +0000955 // Two cases when writing to gl_FragColor and using ESSL 1.0:
956 // - with a 3.0 context, the output color is copied to channel 0
957 // - with a 2.0 context, the output color is broadcast to all channels
958 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
959 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
960
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000961 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000962 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000963 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000964
965 return false;
966 }
967
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000968 vertexShader->resetVaryingsRegisterAssignment();
969
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000970 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
971 {
972 bool matched = false;
973
974 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
975 {
976 if (output->name == input->name)
977 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000978 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000979 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000980 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 +0000981
982 return false;
983 }
984
985 output->reg = input->reg;
986 output->col = input->col;
987
988 matched = true;
989 break;
990 }
991 }
992
993 if (!matched)
994 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000995 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000996
997 return false;
998 }
999 }
1000
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001001 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001002 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001003 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001004 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1005
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001006 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1007
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001008 // special varyings that use reserved registers
1009 int reservedRegisterIndex = registers;
1010 std::string fragCoordSemantic;
1011 std::string pointCoordSemantic;
1012
1013 if (fragmentShader->mUsesFragCoord)
1014 {
1015 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1016 }
1017
1018 if (fragmentShader->mUsesPointCoord)
1019 {
1020 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1021 // In DX11 we compute this in the GS.
1022 if (shaderModel == 3)
1023 {
1024 pointCoordSemantic = "TEXCOORD0";
1025 }
1026 else if (shaderModel >= 4)
1027 {
1028 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1029 }
1030 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001031
1032 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001033 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001034
1035 int semanticIndex = 0;
1036 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1037 {
1038 switch (attribute->type)
1039 {
1040 case GL_FLOAT: vertexHLSL += " float "; break;
1041 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1042 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1043 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1044 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1045 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1046 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1047 default: UNREACHABLE();
1048 }
1049
1050 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1051
1052 semanticIndex += VariableRowCount(attribute->type);
1053 }
1054
1055 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001056 "\n"
1057 "struct VS_OUTPUT\n"
1058 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001059
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001060 if (shaderModel < 4)
1061 {
1062 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1063 }
1064
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001065 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001066
1067 if (fragmentShader->mUsesFragCoord)
1068 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001069 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001070 }
1071
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001072 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001073 {
1074 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1075 }
1076
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001077 if (shaderModel >= 4)
1078 {
1079 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1080 }
1081
1082 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001083 "\n"
1084 "VS_OUTPUT main(VS_INPUT input)\n"
1085 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001086
1087 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1088 {
1089 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1090
1091 if (VariableRowCount(attribute->type) > 1) // Matrix
1092 {
1093 vertexHLSL += "transpose";
1094 }
1095
1096 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1097 }
1098
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001099 if (shaderModel >= 4)
1100 {
1101 vertexHLSL += "\n"
1102 " gl_main();\n"
1103 "\n"
1104 " VS_OUTPUT output;\n"
1105 " output.gl_Position.x = gl_Position.x;\n"
1106 " output.gl_Position.y = -gl_Position.y;\n"
1107 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1108 " output.gl_Position.w = gl_Position.w;\n";
1109 }
1110 else
1111 {
1112 vertexHLSL += "\n"
1113 " gl_main();\n"
1114 "\n"
1115 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001116 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1117 " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001118 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1119 " output.gl_Position.w = gl_Position.w;\n";
1120 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001121
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001122 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001123 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001124 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001125 }
1126
1127 if (fragmentShader->mUsesFragCoord)
1128 {
1129 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1130 }
1131
1132 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1133 {
1134 if (varying->reg >= 0)
1135 {
1136 for (int i = 0; i < varying->size; i++)
1137 {
1138 int rows = VariableRowCount(varying->type);
1139
1140 for (int j = 0; j < rows; j++)
1141 {
1142 int r = varying->reg + i * rows + j;
1143 vertexHLSL += " output.v" + str(r);
1144
1145 bool sharedRegister = false; // Register used by multiple varyings
1146
1147 for (int x = 0; x < 4; x++)
1148 {
1149 if (packing[r][x] && packing[r][x] != packing[r][0])
1150 {
1151 sharedRegister = true;
1152 break;
1153 }
1154 }
1155
1156 if(sharedRegister)
1157 {
1158 vertexHLSL += ".";
1159
1160 for (int x = 0; x < 4; x++)
1161 {
1162 if (packing[r][x] == &*varying)
1163 {
1164 switch(x)
1165 {
1166 case 0: vertexHLSL += "x"; break;
1167 case 1: vertexHLSL += "y"; break;
1168 case 2: vertexHLSL += "z"; break;
1169 case 3: vertexHLSL += "w"; break;
1170 }
1171 }
1172 }
1173 }
1174
1175 vertexHLSL += " = " + varying->name;
1176
1177 if (varying->array)
1178 {
1179 vertexHLSL += "[" + str(i) + "]";
1180 }
1181
1182 if (rows > 1)
1183 {
1184 vertexHLSL += "[" + str(j) + "]";
1185 }
1186
1187 vertexHLSL += ";\n";
1188 }
1189 }
1190 }
1191 }
1192
1193 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001194 " return output;\n"
1195 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001196
1197 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001198 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001199
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001200 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001201
1202 if (fragmentShader->mUsesFragCoord)
1203 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001204 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001205 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001206
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001207 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1208 {
1209 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1210 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001211
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001212 // Must consume the PSIZE element if the geometry shader is not active
1213 // We won't know if we use a GS until we draw
1214 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1215 {
1216 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1217 }
1218
1219 if (fragmentShader->mUsesFragCoord)
1220 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001221 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001222 {
1223 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1224 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001225 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001226 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001227 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1228 }
1229 }
1230
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001231 pixelHLSL += "};\n"
1232 "\n"
1233 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001234 "{\n";
1235
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001236 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001237 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001238 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001239 }
1240
1241 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001242 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001243
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001244 if (fragmentShader->mUsesFrontFacing)
1245 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001246 if (shaderModel >= 4)
1247 {
1248 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1249 "{\n";
1250 }
1251 else
1252 {
1253 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1254 "{\n";
1255 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001256 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001257 else
1258 {
1259 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1260 "{\n";
1261 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262
1263 if (fragmentShader->mUsesFragCoord)
1264 {
1265 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1266
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001267 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001268 {
1269 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1270 " gl_FragCoord.y = input.dx_VPos.y;\n";
1271 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001272 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001273 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001274 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001275 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001276 }
1277 else
1278 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001279 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1280 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1281 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001282 }
1283
daniel@transgaming.com12985182012-12-20 20:56:31 +00001284 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001285 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001286 }
1287
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001288 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001289 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001290 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1291 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001292 }
1293
1294 if (fragmentShader->mUsesFrontFacing)
1295 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001296 if (shaderModel <= 3)
1297 {
1298 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1299 }
1300 else
1301 {
1302 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1303 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001304 }
1305
1306 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1307 {
1308 if (varying->reg >= 0)
1309 {
1310 for (int i = 0; i < varying->size; i++)
1311 {
1312 int rows = VariableRowCount(varying->type);
1313 for (int j = 0; j < rows; j++)
1314 {
1315 std::string n = str(varying->reg + i * rows + j);
1316 pixelHLSL += " " + varying->name;
1317
1318 if (varying->array)
1319 {
1320 pixelHLSL += "[" + str(i) + "]";
1321 }
1322
1323 if (rows > 1)
1324 {
1325 pixelHLSL += "[" + str(j) + "]";
1326 }
1327
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001328 switch (VariableColumnCount(varying->type))
1329 {
1330 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1331 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1332 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1333 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1334 default: UNREACHABLE();
1335 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001336 }
1337 }
1338 }
1339 else UNREACHABLE();
1340 }
1341
1342 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001343 " gl_main();\n"
1344 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001345 " PS_OUTPUT output;\n";
1346
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001347 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001348 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001349 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001350
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001351 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001352 }
1353
1354 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001355 " return output;\n"
1356 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001357
1358 return true;
1359}
1360
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001361std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1362{
1363 std::string varyingHLSL;
1364
1365 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1366 {
1367 if (varying->reg >= 0)
1368 {
1369 for (int i = 0; i < varying->size; i++)
1370 {
1371 int rows = VariableRowCount(varying->type);
1372 for (int j = 0; j < rows; j++)
1373 {
1374 switch (varying->interpolation)
1375 {
1376 case Smooth: varyingHLSL += " "; break;
1377 case Flat: varyingHLSL += " nointerpolation "; break;
1378 case Centroid: varyingHLSL += " centroid "; break;
1379 default: UNREACHABLE();
1380 }
1381
1382 std::string n = str(varying->reg + i * rows + j);
1383 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1384 }
1385 }
1386 }
1387 else UNREACHABLE();
1388 }
1389
1390 return varyingHLSL;
1391}
1392
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001393bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1394{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001395 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001396
1397 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001398 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001399 if (format != GL_PROGRAM_BINARY_ANGLE)
1400 {
1401 infoLog.append("Invalid program binary format.");
1402 return false;
1403 }
1404
1405 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001406 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001407 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001408 {
1409 infoLog.append("Invalid program binary version.");
1410 return false;
1411 }
1412
1413 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1414 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001415 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001416 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001417 stream.read(&name);
1418 mLinkedAttribute[i].name = name;
1419 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001420 }
1421
1422 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1423 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001424 stream.read(&mSamplersPS[i].active);
1425 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001426
1427 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001428 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001429 mSamplersPS[i].textureType = (TextureType) textureType;
1430 }
1431
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001432 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001433 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001434 stream.read(&mSamplersVS[i].active);
1435 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001436
1437 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001438 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001439 mSamplersVS[i].textureType = (TextureType) textureType;
1440 }
1441
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001442 stream.read(&mUsedVertexSamplerRange);
1443 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001444 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001445
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001446 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001447 stream.read(&size);
1448 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001449 {
1450 infoLog.append("Invalid program binary.");
1451 return false;
1452 }
1453
1454 mUniforms.resize(size);
1455 for (unsigned int i = 0; i < size; ++i)
1456 {
1457 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001458 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001459 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001460 unsigned int arraySize;
1461
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001462 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001463 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001464 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001465 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001466
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001467 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001468
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001469 stream.read(&mUniforms[i]->psRegisterIndex);
1470 stream.read(&mUniforms[i]->vsRegisterIndex);
1471 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001472 }
1473
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001474 stream.read(&size);
1475 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001476 {
1477 infoLog.append("Invalid program binary.");
1478 return false;
1479 }
1480
1481 mUniformIndex.resize(size);
1482 for (unsigned int i = 0; i < size; ++i)
1483 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001484 stream.read(&mUniformIndex[i].name);
1485 stream.read(&mUniformIndex[i].element);
1486 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001487 }
1488
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001489 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001490 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001491
1492 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001493 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001494
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001495 unsigned int geometryShaderSize;
1496 stream.read(&geometryShaderSize);
1497
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001498 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001499
daniel@transgaming.com36038542012-11-28 20:59:26 +00001500 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001501 ptr += sizeof(GUID);
1502
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001503 GUID identifier = mRenderer->getAdapterIdentifier();
1504 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001505 {
1506 infoLog.append("Invalid program binary.");
1507 return false;
1508 }
1509
1510 const char *pixelShaderFunction = ptr;
1511 ptr += pixelShaderSize;
1512
1513 const char *vertexShaderFunction = ptr;
1514 ptr += vertexShaderSize;
1515
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001516 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1517 ptr += geometryShaderSize;
1518
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001519 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001520 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001521 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001522 {
1523 infoLog.append("Could not create pixel shader.");
1524 return false;
1525 }
1526
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001527 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001528 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001529 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001530 {
1531 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001532 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001533 mPixelExecutable = NULL;
1534 return false;
1535 }
1536
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001537 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1538 {
1539 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1540 geometryShaderSize, rx::SHADER_GEOMETRY);
1541 if (!mGeometryExecutable)
1542 {
1543 infoLog.append("Could not create geometry shader.");
1544 delete mPixelExecutable;
1545 mPixelExecutable = NULL;
1546 delete mVertexExecutable;
1547 mVertexExecutable = NULL;
1548 return false;
1549 }
1550 }
1551 else
1552 {
1553 mGeometryExecutable = NULL;
1554 }
1555
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001556 return true;
1557}
1558
1559bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1560{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001561 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001562
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001563 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001564 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565
1566 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1567 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001568 stream.write(mLinkedAttribute[i].type);
1569 stream.write(mLinkedAttribute[i].name);
1570 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571 }
1572
1573 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1574 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001575 stream.write(mSamplersPS[i].active);
1576 stream.write(mSamplersPS[i].logicalTextureUnit);
1577 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578 }
1579
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001580 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001581 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001582 stream.write(mSamplersVS[i].active);
1583 stream.write(mSamplersVS[i].logicalTextureUnit);
1584 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001585 }
1586
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001587 stream.write(mUsedVertexSamplerRange);
1588 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001589 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001590
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001591 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1593 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001594 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001595 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001596 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001597 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001599 stream.write(mUniforms[i]->psRegisterIndex);
1600 stream.write(mUniforms[i]->vsRegisterIndex);
1601 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001602 }
1603
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001604 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1606 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001607 stream.write(mUniformIndex[i].name);
1608 stream.write(mUniformIndex[i].element);
1609 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001610 }
1611
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001612 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001613 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001615 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001616 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001618 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1619 stream.write(geometryShaderSize);
1620
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001621 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001622
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001623 GLsizei streamLength = stream.length();
1624 const void *streamData = stream.data();
1625
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001626 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 if (totalLength > bufSize)
1628 {
1629 if (length)
1630 {
1631 *length = 0;
1632 }
1633
1634 return false;
1635 }
1636
1637 if (binary)
1638 {
1639 char *ptr = (char*) binary;
1640
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001641 memcpy(ptr, streamData, streamLength);
1642 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001644 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001645 ptr += sizeof(GUID);
1646
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001647 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001648 ptr += pixelShaderSize;
1649
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001650 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651 ptr += vertexShaderSize;
1652
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001653 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1654 {
1655 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1656 ptr += geometryShaderSize;
1657 }
1658
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001659 ASSERT(ptr - totalLength == binary);
1660 }
1661
1662 if (length)
1663 {
1664 *length = totalLength;
1665 }
1666
1667 return true;
1668}
1669
1670GLint ProgramBinary::getLength()
1671{
1672 GLint length;
1673 if (save(NULL, INT_MAX, &length))
1674 {
1675 return length;
1676 }
1677 else
1678 {
1679 return 0;
1680 }
1681}
1682
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001683bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001684{
1685 if (!fragmentShader || !fragmentShader->isCompiled())
1686 {
1687 return false;
1688 }
1689
1690 if (!vertexShader || !vertexShader->isCompiled())
1691 {
1692 return false;
1693 }
1694
1695 std::string pixelHLSL = fragmentShader->getHLSL();
1696 std::string vertexHLSL = vertexShader->getHLSL();
1697
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001698 // Map the varyings to the register file
1699 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1700 int registers = packVaryings(infoLog, packing, fragmentShader);
1701
1702 if (registers < 0)
1703 {
1704 return false;
1705 }
1706
1707 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001708 {
1709 return false;
1710 }
1711
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001712 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001713 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1714 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001715
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001716 if (usesGeometryShader())
1717 {
1718 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1719 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1720 }
1721
1722 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001723 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001724 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001725 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001726
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001727 delete mVertexExecutable;
1728 mVertexExecutable = NULL;
1729 delete mPixelExecutable;
1730 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001731 delete mGeometryExecutable;
1732 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001733 }
1734
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001735 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1736 {
1737 success = false;
1738 }
1739
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001740 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001741 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001742 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001743 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001744
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001745 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1746 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1747 {
1748 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0));
1749 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0));
1750 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0));
1751 }
1752
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001753 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001754}
1755
1756// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001757bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001758{
1759 unsigned int usedLocations = 0;
1760
1761 // Link attributes that have a binding location
1762 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1763 {
1764 int location = attributeBindings.getAttributeBinding(attribute->name);
1765
1766 if (location != -1) // Set by glBindAttribLocation
1767 {
1768 if (!mLinkedAttribute[location].name.empty())
1769 {
1770 // Multiple active attributes bound to the same location; not an error
1771 }
1772
1773 mLinkedAttribute[location] = *attribute;
1774
1775 int rows = VariableRowCount(attribute->type);
1776
1777 if (rows + location > MAX_VERTEX_ATTRIBS)
1778 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001779 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 +00001780
1781 return false;
1782 }
1783
1784 for (int i = 0; i < rows; i++)
1785 {
1786 usedLocations |= 1 << (location + i);
1787 }
1788 }
1789 }
1790
1791 // Link attributes that don't have a binding location
1792 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1793 {
1794 int location = attributeBindings.getAttributeBinding(attribute->name);
1795
1796 if (location == -1) // Not set by glBindAttribLocation
1797 {
1798 int rows = VariableRowCount(attribute->type);
1799 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1800
1801 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1802 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001803 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001804
1805 return false; // Fail to link
1806 }
1807
1808 mLinkedAttribute[availableIndex] = *attribute;
1809 }
1810 }
1811
1812 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1813 {
1814 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1815 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1816
1817 for (int r = 0; r < rows; r++)
1818 {
1819 mSemanticIndex[attributeIndex++] = index++;
1820 }
1821 }
1822
1823 return true;
1824}
1825
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001826bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001827{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001828 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001829 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001830 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001831 {
1832 return false;
1833 }
1834 }
1835
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001836 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001837 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001838 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001839 {
1840 return false;
1841 }
1842 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001843
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001844 return true;
1845}
1846
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001847bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001848{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001849 if (constant.type == GL_SAMPLER_2D ||
1850 constant.type == GL_SAMPLER_CUBE)
1851 {
1852 unsigned int samplerIndex = constant.registerIndex;
1853
1854 do
1855 {
1856 if (shader == GL_VERTEX_SHADER)
1857 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001858 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001859 {
1860 mSamplersVS[samplerIndex].active = true;
1861 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1862 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1863 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1864 }
1865 else
1866 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001867 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001868 return false;
1869 }
1870 }
1871 else if (shader == GL_FRAGMENT_SHADER)
1872 {
1873 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1874 {
1875 mSamplersPS[samplerIndex].active = true;
1876 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1877 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1878 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1879 }
1880 else
1881 {
1882 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1883 return false;
1884 }
1885 }
1886 else UNREACHABLE();
1887
1888 samplerIndex++;
1889 }
1890 while (samplerIndex < constant.registerIndex + constant.arraySize);
1891 }
1892
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001893 Uniform *uniform = NULL;
1894 GLint location = getUniformLocation(constant.name);
1895
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001896 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001897 {
1898 uniform = mUniforms[mUniformIndex[location].index];
1899
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001900 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001901 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001902 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1903 return false;
1904 }
1905
1906 if (uniform->precision != constant.precision)
1907 {
1908 infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001909 return false;
1910 }
1911 }
1912 else
1913 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001914 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001915 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001916
1917 if (!uniform)
1918 {
1919 return false;
1920 }
1921
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001922 if (shader == GL_FRAGMENT_SHADER)
1923 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001924 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001925 }
1926 else if (shader == GL_VERTEX_SHADER)
1927 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001928 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001929 }
1930 else UNREACHABLE();
1931
1932 if (location >= 0)
1933 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001934 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001935 }
1936
1937 mUniforms.push_back(uniform);
1938 unsigned int uniformIndex = mUniforms.size() - 1;
1939
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001940 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001941 {
1942 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
1943 }
1944
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001945 if (shader == GL_VERTEX_SHADER)
1946 {
1947 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
1948 {
1949 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
1950 return false;
1951 }
1952 }
1953 else if (shader == GL_FRAGMENT_SHADER)
1954 {
1955 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
1956 {
1957 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
1958 return false;
1959 }
1960 }
1961 else UNREACHABLE();
1962
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001963 return true;
1964}
1965
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001966std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
1967{
1968 // for now we only handle point sprite emulation
1969 ASSERT(usesPointSpriteEmulation());
1970 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
1971}
1972
1973std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
1974{
1975 ASSERT(registers >= 0);
1976 ASSERT(vertexShader->mUsesPointSize);
1977 ASSERT(mRenderer->getMajorShaderModel() >= 4);
1978
1979 std::string geomHLSL;
1980
1981 std::string varyingSemantic = "TEXCOORD";
1982
1983 std::string fragCoordSemantic;
1984 std::string pointCoordSemantic;
1985
1986 int reservedRegisterIndex = registers;
1987
1988 if (fragmentShader->mUsesFragCoord)
1989 {
1990 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1991 }
1992
1993 if (fragmentShader->mUsesPointCoord)
1994 {
1995 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1996 }
1997
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001998 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
1999 "\n"
2000 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002001 "{\n";
2002
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002003 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002004
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002005 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002006
2007 if (fragmentShader->mUsesFragCoord)
2008 {
2009 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2010 }
2011
2012 geomHLSL += " float gl_PointSize : PSIZE;\n"
2013 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002014 "};\n"
2015 "\n"
2016 "struct GS_OUTPUT\n"
2017 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002018
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002019 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002020
2021 if (fragmentShader->mUsesFragCoord)
2022 {
2023 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2024 }
2025
2026 if (fragmentShader->mUsesPointCoord)
2027 {
2028 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2029 }
2030
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002031 geomHLSL += " float gl_PointSize : PSIZE;\n"
2032 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002033 "};\n"
2034 "\n"
2035 "static float2 pointSpriteCorners[] = \n"
2036 "{\n"
2037 " float2( 0.5f, -0.5f),\n"
2038 " float2( 0.5f, 0.5f),\n"
2039 " float2(-0.5f, -0.5f),\n"
2040 " float2(-0.5f, 0.5f)\n"
2041 "};\n"
2042 "\n"
2043 "static float2 pointSpriteTexcoords[] = \n"
2044 "{\n"
2045 " float2(1.0f, 1.0f),\n"
2046 " float2(1.0f, 0.0f),\n"
2047 " float2(0.0f, 1.0f),\n"
2048 " float2(0.0f, 0.0f)\n"
2049 "};\n"
2050 "\n"
2051 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2052 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2053 "\n"
2054 "[maxvertexcount(4)]\n"
2055 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2056 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002057 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2058 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002059
2060 for (int r = 0; r < registers; r++)
2061 {
2062 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2063 }
2064
2065 if (fragmentShader->mUsesFragCoord)
2066 {
2067 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2068 }
2069
2070 geomHLSL += " \n"
2071 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2072 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002073 " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002074
2075 for (int corner = 0; corner < 4; corner++)
2076 {
2077 geomHLSL += " \n"
2078 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2079
2080 if (fragmentShader->mUsesPointCoord)
2081 {
2082 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2083 }
2084
2085 geomHLSL += " outStream.Append(output);\n";
2086 }
2087
2088 geomHLSL += " \n"
2089 " outStream.RestartStrip();\n"
2090 "}\n";
2091
2092 return geomHLSL;
2093}
2094
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002095// This method needs to match OutputHLSL::decorate
2096std::string ProgramBinary::decorateAttribute(const std::string &name)
2097{
2098 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2099 {
2100 return "_" + name;
2101 }
2102
2103 return name;
2104}
2105
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002106bool ProgramBinary::isValidated() const
2107{
2108 return mValidated;
2109}
2110
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002111void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002112{
2113 // Skip over inactive attributes
2114 unsigned int activeAttribute = 0;
2115 unsigned int attribute;
2116 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2117 {
2118 if (mLinkedAttribute[attribute].name.empty())
2119 {
2120 continue;
2121 }
2122
2123 if (activeAttribute == index)
2124 {
2125 break;
2126 }
2127
2128 activeAttribute++;
2129 }
2130
2131 if (bufsize > 0)
2132 {
2133 const char *string = mLinkedAttribute[attribute].name.c_str();
2134
2135 strncpy(name, string, bufsize);
2136 name[bufsize - 1] = '\0';
2137
2138 if (length)
2139 {
2140 *length = strlen(name);
2141 }
2142 }
2143
2144 *size = 1; // Always a single 'type' instance
2145
2146 *type = mLinkedAttribute[attribute].type;
2147}
2148
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002149GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002150{
2151 int count = 0;
2152
2153 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2154 {
2155 if (!mLinkedAttribute[attributeIndex].name.empty())
2156 {
2157 count++;
2158 }
2159 }
2160
2161 return count;
2162}
2163
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002164GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002165{
2166 int maxLength = 0;
2167
2168 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2169 {
2170 if (!mLinkedAttribute[attributeIndex].name.empty())
2171 {
2172 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2173 }
2174 }
2175
2176 return maxLength;
2177}
2178
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002179void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002180{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002181 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002182
2183 if (bufsize > 0)
2184 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002185 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002186
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002187 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002188 {
2189 string += "[0]";
2190 }
2191
2192 strncpy(name, string.c_str(), bufsize);
2193 name[bufsize - 1] = '\0';
2194
2195 if (length)
2196 {
2197 *length = strlen(name);
2198 }
2199 }
2200
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002201 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002202
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002203 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002204}
2205
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002206GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002207{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002208 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002209}
2210
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002211GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002212{
2213 int maxLength = 0;
2214
2215 unsigned int numUniforms = mUniforms.size();
2216 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2217 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002218 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002219 {
2220 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2221 if (mUniforms[uniformIndex]->isArray())
2222 {
2223 length += 3; // Counting in "[0]".
2224 }
2225 maxLength = std::max(length, maxLength);
2226 }
2227 }
2228
2229 return maxLength;
2230}
2231
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002232GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2233{
2234 const gl::Uniform& uniform = *mUniforms[index];
2235
2236 switch (pname)
2237 {
2238 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2239 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2240 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
2241
2242 case GL_UNIFORM_BLOCK_INDEX:
2243 case GL_UNIFORM_OFFSET:
2244 case GL_UNIFORM_ARRAY_STRIDE:
2245 case GL_UNIFORM_MATRIX_STRIDE:
2246 // the default block gives a value of -1 for these parameters
2247 return -1;
2248
2249 case GL_UNIFORM_IS_ROW_MAJOR:
2250 // TODO: column/row major layout for uniform blocks
2251 return 0;
2252
2253 default:
2254 UNREACHABLE();
2255 break;
2256 }
2257 return 0;
2258}
2259
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002260void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002261{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002262 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002263 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002264 {
2265 mValidated = false;
2266 }
2267 else
2268 {
2269 mValidated = true;
2270 }
2271}
2272
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002273bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274{
2275 // if any two active samplers in a program are of different types, but refer to the same
2276 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2277 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2278
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002279 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002280 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002281
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002282 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002283 {
2284 textureUnitType[i] = TEXTURE_UNKNOWN;
2285 }
2286
2287 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2288 {
2289 if (mSamplersPS[i].active)
2290 {
2291 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2292
2293 if (unit >= maxCombinedTextureImageUnits)
2294 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002295 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002296 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002297 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002298 }
2299
2300 return false;
2301 }
2302
2303 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2304 {
2305 if (mSamplersPS[i].textureType != textureUnitType[unit])
2306 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002307 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002308 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002309 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002310 }
2311
2312 return false;
2313 }
2314 }
2315 else
2316 {
2317 textureUnitType[unit] = mSamplersPS[i].textureType;
2318 }
2319 }
2320 }
2321
2322 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2323 {
2324 if (mSamplersVS[i].active)
2325 {
2326 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2327
2328 if (unit >= maxCombinedTextureImageUnits)
2329 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002330 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002331 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002332 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002333 }
2334
2335 return false;
2336 }
2337
2338 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2339 {
2340 if (mSamplersVS[i].textureType != textureUnitType[unit])
2341 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002342 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002343 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002344 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002345 }
2346
2347 return false;
2348 }
2349 }
2350 else
2351 {
2352 textureUnitType[unit] = mSamplersVS[i].textureType;
2353 }
2354 }
2355 }
2356
2357 return true;
2358}
2359
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002360ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2361{
2362}
2363
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002364struct AttributeSorter
2365{
2366 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2367 : originalIndices(semanticIndices)
2368 {
2369 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2370 {
2371 indices[i] = i;
2372 }
2373
2374 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2375 }
2376
2377 bool operator()(int a, int b)
2378 {
2379 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2380 }
2381
2382 int indices[MAX_VERTEX_ATTRIBS];
2383 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2384};
2385
2386void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2387{
2388 AttributeSorter sorter(mSemanticIndex);
2389
2390 int oldIndices[MAX_VERTEX_ATTRIBS];
2391 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2392
2393 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2394 {
2395 oldIndices[i] = mSemanticIndex[i];
2396 oldTranslatedAttributes[i] = attributes[i];
2397 }
2398
2399 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2400 {
2401 int oldIndex = sorter.indices[i];
2402 sortedSemanticIndices[i] = oldIndices[oldIndex];
2403 attributes[i] = oldTranslatedAttributes[oldIndex];
2404 }
2405}
2406
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002407}