blob: 7c371220643bff748d1cbc28ea9a148670e6c922 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000025
daniel@transgaming.com88853c52012-12-20 20:56:40 +000026#undef near
27#undef far
28
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029namespace gl
30{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031std::string str(int i)
32{
33 char buffer[20];
34 snprintf(buffer, sizeof(buffer), "%d", i);
35 return buffer;
36}
37
daniel@transgaming.comdb019952012-12-20 21:13:32 +000038UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
39 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000040{
41}
42
daniel@transgaming.come87ca002012-07-24 18:30:43 +000043unsigned int ProgramBinary::mCurrentSerial = 1;
44
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000045ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000047 mPixelExecutable = NULL;
48 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000049 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000050
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000051 mValidated = false;
52
53 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
54 {
55 mSemanticIndex[index] = -1;
56 }
57
58 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
59 {
60 mSamplersPS[index].active = false;
61 }
62
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000063 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000064 {
65 mSamplersVS[index].active = false;
66 }
67
68 mUsedVertexSamplerRange = 0;
69 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000070 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071}
72
73ProgramBinary::~ProgramBinary()
74{
daniel@transgaming.com95892412012-11-28 20:59:09 +000075 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000076 mPixelExecutable = NULL;
77
daniel@transgaming.com95892412012-11-28 20:59:09 +000078 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000079 mVertexExecutable = NULL;
80
81 delete mGeometryExecutable;
82 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000084 while (!mUniforms.empty())
85 {
86 delete mUniforms.back();
87 mUniforms.pop_back();
88 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000089}
90
daniel@transgaming.come87ca002012-07-24 18:30:43 +000091unsigned int ProgramBinary::getSerial() const
92{
93 return mSerial;
94}
95
96unsigned int ProgramBinary::issueSerial()
97{
98 return mCurrentSerial++;
99}
100
daniel@transgaming.com95892412012-11-28 20:59:09 +0000101rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102{
103 return mPixelExecutable;
104}
105
daniel@transgaming.com95892412012-11-28 20:59:09 +0000106rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000107{
108 return mVertexExecutable;
109}
110
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000111rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
112{
113 return mGeometryExecutable;
114}
115
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116GLuint ProgramBinary::getAttributeLocation(const char *name)
117{
118 if (name)
119 {
120 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
121 {
122 if (mLinkedAttribute[index].name == std::string(name))
123 {
124 return index;
125 }
126 }
127 }
128
129 return -1;
130}
131
132int ProgramBinary::getSemanticIndex(int attributeIndex)
133{
134 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
135
136 return mSemanticIndex[attributeIndex];
137}
138
139// Returns one more than the highest sampler index used.
140GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
141{
142 switch (type)
143 {
144 case SAMPLER_PIXEL:
145 return mUsedPixelSamplerRange;
146 case SAMPLER_VERTEX:
147 return mUsedVertexSamplerRange;
148 default:
149 UNREACHABLE();
150 return 0;
151 }
152}
153
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000154bool ProgramBinary::usesPointSize() const
155{
156 return mUsesPointSize;
157}
158
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000159bool ProgramBinary::usesPointSpriteEmulation() const
160{
161 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
162}
163
164bool ProgramBinary::usesGeometryShader() const
165{
166 return usesPointSpriteEmulation();
167}
168
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000169// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
170// index (0-15 for the pixel shader and 0-3 for the vertex shader).
171GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
172{
173 GLint logicalTextureUnit = -1;
174
175 switch (type)
176 {
177 case SAMPLER_PIXEL:
178 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
179
180 if (mSamplersPS[samplerIndex].active)
181 {
182 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
183 }
184 break;
185 case SAMPLER_VERTEX:
186 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
187
188 if (mSamplersVS[samplerIndex].active)
189 {
190 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
191 }
192 break;
193 default: UNREACHABLE();
194 }
195
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000196 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000197 {
198 return logicalTextureUnit;
199 }
200
201 return -1;
202}
203
204// Returns the texture type for a given Direct3D 9 sampler type and
205// index (0-15 for the pixel shader and 0-3 for the vertex shader).
206TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
207{
208 switch (type)
209 {
210 case SAMPLER_PIXEL:
211 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
212 ASSERT(mSamplersPS[samplerIndex].active);
213 return mSamplersPS[samplerIndex].textureType;
214 case SAMPLER_VERTEX:
215 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
216 ASSERT(mSamplersVS[samplerIndex].active);
217 return mSamplersVS[samplerIndex].textureType;
218 default: UNREACHABLE();
219 }
220
221 return TEXTURE_2D;
222}
223
224GLint ProgramBinary::getUniformLocation(std::string name)
225{
226 unsigned int subscript = 0;
227
228 // Strip any trailing array operator and retrieve the subscript
229 size_t open = name.find_last_of('[');
230 size_t close = name.find_last_of(']');
231 if (open != std::string::npos && close == name.length() - 1)
232 {
233 subscript = atoi(name.substr(open + 1).c_str());
234 name.erase(open);
235 }
236
237 unsigned int numUniforms = mUniformIndex.size();
238 for (unsigned int location = 0; location < numUniforms; location++)
239 {
240 if (mUniformIndex[location].name == name &&
241 mUniformIndex[location].element == subscript)
242 {
243 return location;
244 }
245 }
246
247 return -1;
248}
249
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000250template <typename T>
251bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000252{
253 if (location < 0 || location >= (int)mUniformIndex.size())
254 {
255 return false;
256 }
257
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000258 const int components = UniformComponentCount(targetUniformType);
259 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
260
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000261 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
262 targetUniform->dirty = true;
263
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000264 int elementCount = targetUniform->elementCount();
265
266 if (elementCount == 1 && count > 1)
267 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
268
269 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
270
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000271 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000272 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000273 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000274
275 for (int i = 0; i < count; i++)
276 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000277 for (int c = 0; c < components; c++)
278 {
279 target[c] = v[c];
280 }
281 for (int c = components; c < 4; c++)
282 {
283 target[c] = 0;
284 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000285 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000286 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000287 }
288 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000289 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000290 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000291 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000292
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000293 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000294 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000295 for (int c = 0; c < components; c++)
296 {
297 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
298 }
299 for (int c = components; c < 4; c++)
300 {
301 boolParams[c] = GL_FALSE;
302 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000303 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000304 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000305 }
306 }
307 else
308 {
309 return false;
310 }
311
312 return true;
313}
314
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000315bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
316{
317 return setUniform(location, count, v, GL_FLOAT);
318}
319
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000320bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
321{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000322 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000323}
324
325bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
326{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000327 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000328}
329
330bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
331{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000332 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000333}
334
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000335template<typename T>
336void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000337{
338 int copyWidth = std::min(targetWidth, srcWidth);
339 int copyHeight = std::min(targetHeight, srcHeight);
340
341 for (int x = 0; x < copyWidth; x++)
342 {
343 for (int y = 0; y < copyHeight; y++)
344 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000345 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000346 }
347 }
348 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000349 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000350 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000351 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000352 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000353 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000354 }
355 }
356 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000357 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000358 {
359 for (int x = 0; x < targetWidth; x++)
360 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000361 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000362 }
363 }
364}
365
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000366template<typename T>
367void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
368{
369 int copyWidth = std::min(targetWidth, srcWidth);
370 int copyHeight = std::min(targetHeight, srcHeight);
371
372 for (int y = 0; y < copyHeight; y++)
373 {
374 for (int x = 0; x < copyWidth; x++)
375 {
376 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
377 }
378 }
379 // clear unfilled right side
380 for (int y = 0; y < copyHeight; y++)
381 {
382 for (int x = copyWidth; x < targetWidth; x++)
383 {
384 target[y * targetWidth + x] = static_cast<T>(0);
385 }
386 }
387 // clear unfilled bottom.
388 for (int y = copyHeight; y < targetHeight; y++)
389 {
390 for (int x = 0; x < targetWidth; x++)
391 {
392 target[y * targetWidth + x] = static_cast<T>(0);
393 }
394 }
395}
396
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000397template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000398bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399{
400 if (location < 0 || location >= (int)mUniformIndex.size())
401 {
402 return false;
403 }
404
405 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
406 targetUniform->dirty = true;
407
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000408 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000409 {
410 return false;
411 }
412
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000413 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000414
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000415 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000416 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
417
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000418 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000419 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4 * rows);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000420
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000421 for (int i = 0; i < count; i++)
422 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000423 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
424 if (transpose == GL_FALSE)
425 {
426 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
427 }
428 else
429 {
430 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
431 }
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000432 target += 4 * rows;
433 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000434 }
435
436 return true;
437}
438
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000439bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000440{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000441 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000442}
443
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000444bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000446 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000447}
448
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000449bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000450{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000451 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452}
453
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000454bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000455{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000456 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000457}
458
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000459bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000460{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000461 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000462}
463
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000464bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000465{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000466 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000467}
468
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000469bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000470{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000471 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000472}
473
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000474bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000475{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000476 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000477}
478
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000479bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000480{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000481 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000482}
483
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000484bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
485{
486 if (location < 0 || location >= (int)mUniformIndex.size())
487 {
488 return false;
489 }
490
491 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
492 targetUniform->dirty = true;
493
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000494 int elementCount = targetUniform->elementCount();
495
496 if (elementCount == 1 && count > 1)
497 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
498
499 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
500
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501 if (targetUniform->type == GL_INT ||
502 targetUniform->type == GL_SAMPLER_2D ||
503 targetUniform->type == GL_SAMPLER_CUBE)
504 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000505 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000506
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000507 for (int i = 0; i < count; i++)
508 {
509 target[0] = v[0];
510 target[1] = 0;
511 target[2] = 0;
512 target[3] = 0;
513 target += 4;
514 v += 1;
515 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000516 }
517 else if (targetUniform->type == GL_BOOL)
518 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000519 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000520
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000521 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000522 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000523 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
524 boolParams[1] = GL_FALSE;
525 boolParams[2] = GL_FALSE;
526 boolParams[3] = GL_FALSE;
527 boolParams += 4;
528 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529 }
530 }
531 else
532 {
533 return false;
534 }
535
536 return true;
537}
538
539bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
540{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000541 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542}
543
544bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
545{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000546 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000547}
548
549bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
550{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000551 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000552}
553
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000554bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
555{
556 return setUniform(location, count, v, GL_UNSIGNED_INT);
557}
558
559bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
560{
561 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
562}
563
564bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
565{
566 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
567}
568
569bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
570{
571 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
572}
573
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000574bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
575{
576 if (location < 0 || location >= (int)mUniformIndex.size())
577 {
578 return false;
579 }
580
581 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
582
583 // sized queries -- ensure the provided buffer is large enough
584 if (bufSize)
585 {
586 int requiredBytes = UniformExternalSize(targetUniform->type);
587 if (*bufSize < requiredBytes)
588 {
589 return false;
590 }
591 }
592
593 switch (targetUniform->type)
594 {
595 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000596 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000597 break;
598 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000599 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600 break;
601 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000602 transposeMatrix<GLfloat>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000603 break;
604 default:
605 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000606 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000607
608 switch (UniformComponentType(targetUniform->type))
609 {
610 case GL_BOOL:
611 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000612 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000614 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000615 {
616 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
617 }
618 }
619 break;
620 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000621 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
622 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000623 break;
624 case GL_INT:
625 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000626 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000627
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000628 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629 {
630 params[i] = (float)intParams[i];
631 }
632 }
633 break;
634 default: UNREACHABLE();
635 }
636 }
637 }
638
639 return true;
640}
641
642bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
643{
644 if (location < 0 || location >= (int)mUniformIndex.size())
645 {
646 return false;
647 }
648
649 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
650
651 // sized queries -- ensure the provided buffer is large enough
652 if (bufSize)
653 {
654 int requiredBytes = UniformExternalSize(targetUniform->type);
655 if (*bufSize < requiredBytes)
656 {
657 return false;
658 }
659 }
660
661 switch (targetUniform->type)
662 {
663 case GL_FLOAT_MAT2:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000664 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8, 2, 2, 4, 2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665 break;
666 case GL_FLOAT_MAT3:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000667 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12, 3, 3, 4, 3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668 break;
669 case GL_FLOAT_MAT4:
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000670 transposeMatrix<GLint>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16, 4, 4, 4, 4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000671 break;
672 default:
673 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000674 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000675
676 switch (UniformComponentType(targetUniform->type))
677 {
678 case GL_BOOL:
679 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000680 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000681
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000682 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000683 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000684 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000685 }
686 }
687 break;
688 case GL_FLOAT:
689 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000690 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000691
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000692 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693 {
694 params[i] = (GLint)floatParams[i];
695 }
696 }
697 break;
698 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000699 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
700 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000701 break;
702 default: UNREACHABLE();
703 }
704 }
705 }
706
707 return true;
708}
709
710void ProgramBinary::dirtyAllUniforms()
711{
712 unsigned int numUniforms = mUniforms.size();
713 for (unsigned int index = 0; index < numUniforms; index++)
714 {
715 mUniforms[index]->dirty = true;
716 }
717}
718
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000719// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720void ProgramBinary::applyUniforms()
721{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000722 // Retrieve sampler uniform values
723 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
724 {
725 Uniform *targetUniform = *ub;
726
727 if (targetUniform->dirty)
728 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000729 if (targetUniform->type == GL_SAMPLER_2D ||
730 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000731 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000732 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000733 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000734
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000735 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000736 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000737 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000738
739 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000740 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000741 unsigned int samplerIndex = firstIndex + i;
742
743 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000744 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000745 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000746 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000747 }
748 }
749 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000750
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000751 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000752 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000753 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000754
755 for (int i = 0; i < count; i++)
756 {
757 unsigned int samplerIndex = firstIndex + i;
758
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000759 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000760 {
761 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000762 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000763 }
764 }
765 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000766 }
767 }
768 }
769
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000770 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000771}
772
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
774// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000775int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000776{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000777 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000778
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000779 fragmentShader->resetVaryingsRegisterAssignment();
780
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000781 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
782 {
783 int n = VariableRowCount(varying->type) * varying->size;
784 int m = VariableColumnCount(varying->type);
785 bool success = false;
786
787 if (m == 2 || m == 3 || m == 4)
788 {
789 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
790 {
791 bool available = true;
792
793 for (int y = 0; y < n && available; y++)
794 {
795 for (int x = 0; x < m && available; x++)
796 {
797 if (packing[r + y][x])
798 {
799 available = false;
800 }
801 }
802 }
803
804 if (available)
805 {
806 varying->reg = r;
807 varying->col = 0;
808
809 for (int y = 0; y < n; y++)
810 {
811 for (int x = 0; x < m; x++)
812 {
813 packing[r + y][x] = &*varying;
814 }
815 }
816
817 success = true;
818 }
819 }
820
821 if (!success && m == 2)
822 {
823 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
824 {
825 bool available = true;
826
827 for (int y = 0; y < n && available; y++)
828 {
829 for (int x = 2; x < 4 && available; x++)
830 {
831 if (packing[r + y][x])
832 {
833 available = false;
834 }
835 }
836 }
837
838 if (available)
839 {
840 varying->reg = r;
841 varying->col = 2;
842
843 for (int y = 0; y < n; y++)
844 {
845 for (int x = 2; x < 4; x++)
846 {
847 packing[r + y][x] = &*varying;
848 }
849 }
850
851 success = true;
852 }
853 }
854 }
855 }
856 else if (m == 1)
857 {
858 int space[4] = {0};
859
860 for (int y = 0; y < maxVaryingVectors; y++)
861 {
862 for (int x = 0; x < 4; x++)
863 {
864 space[x] += packing[y][x] ? 0 : 1;
865 }
866 }
867
868 int column = 0;
869
870 for (int x = 0; x < 4; x++)
871 {
872 if (space[x] >= n && space[x] < space[column])
873 {
874 column = x;
875 }
876 }
877
878 if (space[column] >= n)
879 {
880 for (int r = 0; r < maxVaryingVectors; r++)
881 {
882 if (!packing[r][column])
883 {
884 varying->reg = r;
885
886 for (int y = r; y < r + n; y++)
887 {
888 packing[y][column] = &*varying;
889 }
890
891 break;
892 }
893 }
894
895 varying->col = column;
896
897 success = true;
898 }
899 }
900 else UNREACHABLE();
901
902 if (!success)
903 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000904 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000905
906 return -1;
907 }
908 }
909
910 // Return the number of used registers
911 int registers = 0;
912
913 for (int r = 0; r < maxVaryingVectors; r++)
914 {
915 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
916 {
917 registers++;
918 }
919 }
920
921 return registers;
922}
923
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000924bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
925 std::string& pixelHLSL, std::string& vertexHLSL,
926 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000927{
928 if (pixelHLSL.empty() || vertexHLSL.empty())
929 {
930 return false;
931 }
932
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000933 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
934 bool usesFragColor = fragmentShader->mUsesFragColor;
935 bool usesFragData = fragmentShader->mUsesFragData;
936 if (usesMRT && usesFragColor && usesFragData)
937 {
938 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
939 return false;
940 }
941
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000942 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +0000943 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000944 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000945
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000946 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
947
948 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000949 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000950 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000951
952 return false;
953 }
954
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000955 vertexShader->resetVaryingsRegisterAssignment();
956
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000957 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
958 {
959 bool matched = false;
960
961 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
962 {
963 if (output->name == input->name)
964 {
965 if (output->type != input->type || output->size != input->size)
966 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000967 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 +0000968
969 return false;
970 }
971
972 output->reg = input->reg;
973 output->col = input->col;
974
975 matched = true;
976 break;
977 }
978 }
979
980 if (!matched)
981 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000982 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000983
984 return false;
985 }
986 }
987
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000988 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000989 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +0000990 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000991 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
992
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000993 const unsigned int renderTargetCount = usesMRT ? mRenderer->getMaxRenderTargets() : 1;
994
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +0000995 // special varyings that use reserved registers
996 int reservedRegisterIndex = registers;
997 std::string fragCoordSemantic;
998 std::string pointCoordSemantic;
999
1000 if (fragmentShader->mUsesFragCoord)
1001 {
1002 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1003 }
1004
1005 if (fragmentShader->mUsesPointCoord)
1006 {
1007 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1008 // In DX11 we compute this in the GS.
1009 if (shaderModel == 3)
1010 {
1011 pointCoordSemantic = "TEXCOORD0";
1012 }
1013 else if (shaderModel >= 4)
1014 {
1015 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1016 }
1017 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001018
1019 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001020 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001021
1022 int semanticIndex = 0;
1023 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1024 {
1025 switch (attribute->type)
1026 {
1027 case GL_FLOAT: vertexHLSL += " float "; break;
1028 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1029 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1030 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1031 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1032 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1033 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1034 default: UNREACHABLE();
1035 }
1036
1037 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1038
1039 semanticIndex += VariableRowCount(attribute->type);
1040 }
1041
1042 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001043 "\n"
1044 "struct VS_OUTPUT\n"
1045 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001046
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001047 if (shaderModel < 4)
1048 {
1049 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1050 }
1051
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052 for (int r = 0; r < registers; r++)
1053 {
1054 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1055
1056 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1057 }
1058
1059 if (fragmentShader->mUsesFragCoord)
1060 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001061 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001062 }
1063
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001064 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001065 {
1066 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1067 }
1068
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001069 if (shaderModel >= 4)
1070 {
1071 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1072 }
1073
1074 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001075 "\n"
1076 "VS_OUTPUT main(VS_INPUT input)\n"
1077 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001078
1079 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1080 {
1081 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1082
1083 if (VariableRowCount(attribute->type) > 1) // Matrix
1084 {
1085 vertexHLSL += "transpose";
1086 }
1087
1088 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1089 }
1090
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001091 if (shaderModel >= 4)
1092 {
1093 vertexHLSL += "\n"
1094 " gl_main();\n"
1095 "\n"
1096 " VS_OUTPUT output;\n"
1097 " output.gl_Position.x = gl_Position.x;\n"
1098 " output.gl_Position.y = -gl_Position.y;\n"
1099 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1100 " output.gl_Position.w = gl_Position.w;\n";
1101 }
1102 else
1103 {
1104 vertexHLSL += "\n"
1105 " gl_main();\n"
1106 "\n"
1107 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001108 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1109 " 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 +00001110 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1111 " output.gl_Position.w = gl_Position.w;\n";
1112 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001113
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001114 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001115 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001116 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001117 }
1118
1119 if (fragmentShader->mUsesFragCoord)
1120 {
1121 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1122 }
1123
1124 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1125 {
1126 if (varying->reg >= 0)
1127 {
1128 for (int i = 0; i < varying->size; i++)
1129 {
1130 int rows = VariableRowCount(varying->type);
1131
1132 for (int j = 0; j < rows; j++)
1133 {
1134 int r = varying->reg + i * rows + j;
1135 vertexHLSL += " output.v" + str(r);
1136
1137 bool sharedRegister = false; // Register used by multiple varyings
1138
1139 for (int x = 0; x < 4; x++)
1140 {
1141 if (packing[r][x] && packing[r][x] != packing[r][0])
1142 {
1143 sharedRegister = true;
1144 break;
1145 }
1146 }
1147
1148 if(sharedRegister)
1149 {
1150 vertexHLSL += ".";
1151
1152 for (int x = 0; x < 4; x++)
1153 {
1154 if (packing[r][x] == &*varying)
1155 {
1156 switch(x)
1157 {
1158 case 0: vertexHLSL += "x"; break;
1159 case 1: vertexHLSL += "y"; break;
1160 case 2: vertexHLSL += "z"; break;
1161 case 3: vertexHLSL += "w"; break;
1162 }
1163 }
1164 }
1165 }
1166
1167 vertexHLSL += " = " + varying->name;
1168
1169 if (varying->array)
1170 {
1171 vertexHLSL += "[" + str(i) + "]";
1172 }
1173
1174 if (rows > 1)
1175 {
1176 vertexHLSL += "[" + str(j) + "]";
1177 }
1178
1179 vertexHLSL += ";\n";
1180 }
1181 }
1182 }
1183 }
1184
1185 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001186 " return output;\n"
1187 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001188
1189 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001190 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001191
1192 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1193 {
1194 if (varying->reg >= 0)
1195 {
1196 for (int i = 0; i < varying->size; i++)
1197 {
1198 int rows = VariableRowCount(varying->type);
1199 for (int j = 0; j < rows; j++)
1200 {
1201 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001202 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001203 }
1204 }
1205 }
1206 else UNREACHABLE();
1207 }
1208
1209 if (fragmentShader->mUsesFragCoord)
1210 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001211 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001212 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001213
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001214 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1215 {
1216 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1217 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001218
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001219 // Must consume the PSIZE element if the geometry shader is not active
1220 // We won't know if we use a GS until we draw
1221 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1222 {
1223 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1224 }
1225
1226 if (fragmentShader->mUsesFragCoord)
1227 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001228 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001229 {
1230 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1231 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001232 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001233 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1235 }
1236 }
1237
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001238 pixelHLSL += "};\n"
1239 "\n"
1240 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001241 "{\n";
1242
1243 for (unsigned int i = 0; i < renderTargetCount; i++)
1244 {
1245 pixelHLSL += " float4 gl_Color" + str(i) + " : " + targetSemantic + str(i) + ";\n";
1246 }
1247
1248 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001249 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001250
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001251 if (fragmentShader->mUsesFrontFacing)
1252 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001253 if (shaderModel >= 4)
1254 {
1255 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1256 "{\n";
1257 }
1258 else
1259 {
1260 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1261 "{\n";
1262 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001263 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001264 else
1265 {
1266 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1267 "{\n";
1268 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001269
1270 if (fragmentShader->mUsesFragCoord)
1271 {
1272 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1273
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001274 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001275 {
1276 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1277 " gl_FragCoord.y = input.dx_VPos.y;\n";
1278 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001279 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001280 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001282 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001283 }
1284 else
1285 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001286 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1287 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1288 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001289 }
1290
daniel@transgaming.com12985182012-12-20 20:56:31 +00001291 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001292 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001293 }
1294
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001295 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001296 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001297 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1298 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001299 }
1300
1301 if (fragmentShader->mUsesFrontFacing)
1302 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001303 if (shaderModel <= 3)
1304 {
1305 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1306 }
1307 else
1308 {
1309 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1310 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001311 }
1312
1313 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1314 {
1315 if (varying->reg >= 0)
1316 {
1317 for (int i = 0; i < varying->size; i++)
1318 {
1319 int rows = VariableRowCount(varying->type);
1320 for (int j = 0; j < rows; j++)
1321 {
1322 std::string n = str(varying->reg + i * rows + j);
1323 pixelHLSL += " " + varying->name;
1324
1325 if (varying->array)
1326 {
1327 pixelHLSL += "[" + str(i) + "]";
1328 }
1329
1330 if (rows > 1)
1331 {
1332 pixelHLSL += "[" + str(j) + "]";
1333 }
1334
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001335 switch (VariableColumnCount(varying->type))
1336 {
1337 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1338 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1339 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1340 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1341 default: UNREACHABLE();
1342 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001343 }
1344 }
1345 }
1346 else UNREACHABLE();
1347 }
1348
1349 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001350 " gl_main();\n"
1351 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001352 " PS_OUTPUT output;\n";
1353
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001354 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1355 // - with a 3.0 context, the output color is copied to channel 0
1356 // - with a 2.0 context using EXT_draw_buffers, the output color is broadcast to all channels
1357 const bool broadcast = fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3;
1358
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001359 for (unsigned int i = 0; i < renderTargetCount; i++)
1360 {
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +00001361 unsigned int sourceColor = !broadcast ? i : 0;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001362
1363 pixelHLSL += " output.gl_Color" + str(i) + " = gl_Color[" + str(sourceColor) + "];\n";
1364 }
1365
1366 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001367 " return output;\n"
1368 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001369
1370 return true;
1371}
1372
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001373bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1374{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001375 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001376
1377 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001378 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001379 if (format != GL_PROGRAM_BINARY_ANGLE)
1380 {
1381 infoLog.append("Invalid program binary format.");
1382 return false;
1383 }
1384
1385 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001386 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001387 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001388 {
1389 infoLog.append("Invalid program binary version.");
1390 return false;
1391 }
1392
1393 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1394 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001395 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001396 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001397 stream.read(&name);
1398 mLinkedAttribute[i].name = name;
1399 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001400 }
1401
1402 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1403 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001404 stream.read(&mSamplersPS[i].active);
1405 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001406
1407 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001408 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001409 mSamplersPS[i].textureType = (TextureType) textureType;
1410 }
1411
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001412 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001413 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001414 stream.read(&mSamplersVS[i].active);
1415 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001416
1417 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001418 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001419 mSamplersVS[i].textureType = (TextureType) textureType;
1420 }
1421
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001422 stream.read(&mUsedVertexSamplerRange);
1423 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001424 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001425
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001426 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001427 stream.read(&size);
1428 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001429 {
1430 infoLog.append("Invalid program binary.");
1431 return false;
1432 }
1433
1434 mUniforms.resize(size);
1435 for (unsigned int i = 0; i < size; ++i)
1436 {
1437 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001438 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001439 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001440 unsigned int arraySize;
1441
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001442 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001443 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001444 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001445 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001446
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001447 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001448
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001449 stream.read(&mUniforms[i]->psRegisterIndex);
1450 stream.read(&mUniforms[i]->vsRegisterIndex);
1451 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001452 }
1453
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001454 stream.read(&size);
1455 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001456 {
1457 infoLog.append("Invalid program binary.");
1458 return false;
1459 }
1460
1461 mUniformIndex.resize(size);
1462 for (unsigned int i = 0; i < size; ++i)
1463 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001464 stream.read(&mUniformIndex[i].name);
1465 stream.read(&mUniformIndex[i].element);
1466 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001467 }
1468
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001469 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001470 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001471
1472 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001473 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001474
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001475 unsigned int geometryShaderSize;
1476 stream.read(&geometryShaderSize);
1477
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001478 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001479
daniel@transgaming.com36038542012-11-28 20:59:26 +00001480 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001481 ptr += sizeof(GUID);
1482
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001483 GUID identifier = mRenderer->getAdapterIdentifier();
1484 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001485 {
1486 infoLog.append("Invalid program binary.");
1487 return false;
1488 }
1489
1490 const char *pixelShaderFunction = ptr;
1491 ptr += pixelShaderSize;
1492
1493 const char *vertexShaderFunction = ptr;
1494 ptr += vertexShaderSize;
1495
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001496 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1497 ptr += geometryShaderSize;
1498
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001499 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001500 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001501 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001502 {
1503 infoLog.append("Could not create pixel shader.");
1504 return false;
1505 }
1506
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001507 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001508 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001509 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001510 {
1511 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001512 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001513 mPixelExecutable = NULL;
1514 return false;
1515 }
1516
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001517 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1518 {
1519 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1520 geometryShaderSize, rx::SHADER_GEOMETRY);
1521 if (!mGeometryExecutable)
1522 {
1523 infoLog.append("Could not create geometry shader.");
1524 delete mPixelExecutable;
1525 mPixelExecutable = NULL;
1526 delete mVertexExecutable;
1527 mVertexExecutable = NULL;
1528 return false;
1529 }
1530 }
1531 else
1532 {
1533 mGeometryExecutable = NULL;
1534 }
1535
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001536 return true;
1537}
1538
1539bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1540{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001541 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001542
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001543 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001544 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001545
1546 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1547 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001548 stream.write(mLinkedAttribute[i].type);
1549 stream.write(mLinkedAttribute[i].name);
1550 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 }
1552
1553 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1554 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001555 stream.write(mSamplersPS[i].active);
1556 stream.write(mSamplersPS[i].logicalTextureUnit);
1557 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001558 }
1559
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001560 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001562 stream.write(mSamplersVS[i].active);
1563 stream.write(mSamplersVS[i].logicalTextureUnit);
1564 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565 }
1566
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001567 stream.write(mUsedVertexSamplerRange);
1568 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001569 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001570
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001571 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001572 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1573 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001574 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001575 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001576 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001577 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001579 stream.write(mUniforms[i]->psRegisterIndex);
1580 stream.write(mUniforms[i]->vsRegisterIndex);
1581 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001582 }
1583
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001584 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001585 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1586 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001587 stream.write(mUniformIndex[i].name);
1588 stream.write(mUniformIndex[i].element);
1589 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001590 }
1591
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001592 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001593 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001594
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001595 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001596 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001597
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001598 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1599 stream.write(geometryShaderSize);
1600
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001601 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001602
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001603 GLsizei streamLength = stream.length();
1604 const void *streamData = stream.data();
1605
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001606 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001607 if (totalLength > bufSize)
1608 {
1609 if (length)
1610 {
1611 *length = 0;
1612 }
1613
1614 return false;
1615 }
1616
1617 if (binary)
1618 {
1619 char *ptr = (char*) binary;
1620
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001621 memcpy(ptr, streamData, streamLength);
1622 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001624 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001625 ptr += sizeof(GUID);
1626
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001627 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001628 ptr += pixelShaderSize;
1629
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001630 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631 ptr += vertexShaderSize;
1632
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001633 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1634 {
1635 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1636 ptr += geometryShaderSize;
1637 }
1638
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001639 ASSERT(ptr - totalLength == binary);
1640 }
1641
1642 if (length)
1643 {
1644 *length = totalLength;
1645 }
1646
1647 return true;
1648}
1649
1650GLint ProgramBinary::getLength()
1651{
1652 GLint length;
1653 if (save(NULL, INT_MAX, &length))
1654 {
1655 return length;
1656 }
1657 else
1658 {
1659 return 0;
1660 }
1661}
1662
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001663bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001664{
1665 if (!fragmentShader || !fragmentShader->isCompiled())
1666 {
1667 return false;
1668 }
1669
1670 if (!vertexShader || !vertexShader->isCompiled())
1671 {
1672 return false;
1673 }
1674
1675 std::string pixelHLSL = fragmentShader->getHLSL();
1676 std::string vertexHLSL = vertexShader->getHLSL();
1677
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001678 // Map the varyings to the register file
1679 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1680 int registers = packVaryings(infoLog, packing, fragmentShader);
1681
1682 if (registers < 0)
1683 {
1684 return false;
1685 }
1686
1687 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001688 {
1689 return false;
1690 }
1691
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001692 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001693 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1694 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001695
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001696 if (usesGeometryShader())
1697 {
1698 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1699 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1700 }
1701
1702 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001703 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001704 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001705 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001706
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001707 delete mVertexExecutable;
1708 mVertexExecutable = NULL;
1709 delete mPixelExecutable;
1710 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001711 delete mGeometryExecutable;
1712 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001713 }
1714
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001715 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1716 {
1717 success = false;
1718 }
1719
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001720 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001721 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001722 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001723 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001724
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001725 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001726}
1727
1728// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001729bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001730{
1731 unsigned int usedLocations = 0;
1732
1733 // Link attributes that have a binding location
1734 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1735 {
1736 int location = attributeBindings.getAttributeBinding(attribute->name);
1737
1738 if (location != -1) // Set by glBindAttribLocation
1739 {
1740 if (!mLinkedAttribute[location].name.empty())
1741 {
1742 // Multiple active attributes bound to the same location; not an error
1743 }
1744
1745 mLinkedAttribute[location] = *attribute;
1746
1747 int rows = VariableRowCount(attribute->type);
1748
1749 if (rows + location > MAX_VERTEX_ATTRIBS)
1750 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001751 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 +00001752
1753 return false;
1754 }
1755
1756 for (int i = 0; i < rows; i++)
1757 {
1758 usedLocations |= 1 << (location + i);
1759 }
1760 }
1761 }
1762
1763 // Link attributes that don't have a binding location
1764 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1765 {
1766 int location = attributeBindings.getAttributeBinding(attribute->name);
1767
1768 if (location == -1) // Not set by glBindAttribLocation
1769 {
1770 int rows = VariableRowCount(attribute->type);
1771 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1772
1773 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1774 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001775 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001776
1777 return false; // Fail to link
1778 }
1779
1780 mLinkedAttribute[availableIndex] = *attribute;
1781 }
1782 }
1783
1784 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1785 {
1786 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1787 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1788
1789 for (int r = 0; r < rows; r++)
1790 {
1791 mSemanticIndex[attributeIndex++] = index++;
1792 }
1793 }
1794
1795 return true;
1796}
1797
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001798bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001799{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001800 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001801 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001802 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001803 {
1804 return false;
1805 }
1806 }
1807
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001808 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001809 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001810 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001811 {
1812 return false;
1813 }
1814 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001815
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001816 return true;
1817}
1818
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001819bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001820{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001821 if (constant.type == GL_SAMPLER_2D ||
1822 constant.type == GL_SAMPLER_CUBE)
1823 {
1824 unsigned int samplerIndex = constant.registerIndex;
1825
1826 do
1827 {
1828 if (shader == GL_VERTEX_SHADER)
1829 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001830 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001831 {
1832 mSamplersVS[samplerIndex].active = true;
1833 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1834 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1835 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1836 }
1837 else
1838 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001839 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001840 return false;
1841 }
1842 }
1843 else if (shader == GL_FRAGMENT_SHADER)
1844 {
1845 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1846 {
1847 mSamplersPS[samplerIndex].active = true;
1848 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
1849 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1850 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1851 }
1852 else
1853 {
1854 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1855 return false;
1856 }
1857 }
1858 else UNREACHABLE();
1859
1860 samplerIndex++;
1861 }
1862 while (samplerIndex < constant.registerIndex + constant.arraySize);
1863 }
1864
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001865 Uniform *uniform = NULL;
1866 GLint location = getUniformLocation(constant.name);
1867
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001868 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001869 {
1870 uniform = mUniforms[mUniformIndex[location].index];
1871
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001872 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001873 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00001874 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
1875 return false;
1876 }
1877
1878 if (uniform->precision != constant.precision)
1879 {
1880 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 +00001881 return false;
1882 }
1883 }
1884 else
1885 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001886 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001887 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001888
1889 if (!uniform)
1890 {
1891 return false;
1892 }
1893
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001894 if (shader == GL_FRAGMENT_SHADER)
1895 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001896 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001897 }
1898 else if (shader == GL_VERTEX_SHADER)
1899 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001900 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001901 }
1902 else UNREACHABLE();
1903
1904 if (location >= 0)
1905 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001906 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001907 }
1908
1909 mUniforms.push_back(uniform);
1910 unsigned int uniformIndex = mUniforms.size() - 1;
1911
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001912 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001913 {
1914 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
1915 }
1916
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001917 if (shader == GL_VERTEX_SHADER)
1918 {
1919 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
1920 {
1921 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
1922 return false;
1923 }
1924 }
1925 else if (shader == GL_FRAGMENT_SHADER)
1926 {
1927 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
1928 {
1929 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
1930 return false;
1931 }
1932 }
1933 else UNREACHABLE();
1934
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001935 return true;
1936}
1937
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001938std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
1939{
1940 // for now we only handle point sprite emulation
1941 ASSERT(usesPointSpriteEmulation());
1942 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
1943}
1944
1945std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
1946{
1947 ASSERT(registers >= 0);
1948 ASSERT(vertexShader->mUsesPointSize);
1949 ASSERT(mRenderer->getMajorShaderModel() >= 4);
1950
1951 std::string geomHLSL;
1952
1953 std::string varyingSemantic = "TEXCOORD";
1954
1955 std::string fragCoordSemantic;
1956 std::string pointCoordSemantic;
1957
1958 int reservedRegisterIndex = registers;
1959
1960 if (fragmentShader->mUsesFragCoord)
1961 {
1962 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1963 }
1964
1965 if (fragmentShader->mUsesPointCoord)
1966 {
1967 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1968 }
1969
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001970 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
1971 "\n"
1972 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001973 "{\n";
1974
1975 for (int r = 0; r < registers; r++)
1976 {
1977 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1978
1979 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1980 }
1981
1982 if (fragmentShader->mUsesFragCoord)
1983 {
1984 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
1985 }
1986
1987 geomHLSL += " float gl_PointSize : PSIZE;\n"
1988 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001989 "};\n"
1990 "\n"
1991 "struct GS_OUTPUT\n"
1992 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001993
1994 for (int r = 0; r < registers; r++)
1995 {
1996 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1997
1998 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1999 }
2000
2001 if (fragmentShader->mUsesFragCoord)
2002 {
2003 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2004 }
2005
2006 if (fragmentShader->mUsesPointCoord)
2007 {
2008 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2009 }
2010
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002011 geomHLSL += " float gl_PointSize : PSIZE;\n"
2012 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002013 "};\n"
2014 "\n"
2015 "static float2 pointSpriteCorners[] = \n"
2016 "{\n"
2017 " float2( 0.5f, -0.5f),\n"
2018 " float2( 0.5f, 0.5f),\n"
2019 " float2(-0.5f, -0.5f),\n"
2020 " float2(-0.5f, 0.5f)\n"
2021 "};\n"
2022 "\n"
2023 "static float2 pointSpriteTexcoords[] = \n"
2024 "{\n"
2025 " float2(1.0f, 1.0f),\n"
2026 " float2(1.0f, 0.0f),\n"
2027 " float2(0.0f, 1.0f),\n"
2028 " float2(0.0f, 0.0f)\n"
2029 "};\n"
2030 "\n"
2031 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2032 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2033 "\n"
2034 "[maxvertexcount(4)]\n"
2035 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2036 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002037 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2038 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002039
2040 for (int r = 0; r < registers; r++)
2041 {
2042 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2043 }
2044
2045 if (fragmentShader->mUsesFragCoord)
2046 {
2047 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2048 }
2049
2050 geomHLSL += " \n"
2051 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2052 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002053 " 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 +00002054
2055 for (int corner = 0; corner < 4; corner++)
2056 {
2057 geomHLSL += " \n"
2058 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2059
2060 if (fragmentShader->mUsesPointCoord)
2061 {
2062 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2063 }
2064
2065 geomHLSL += " outStream.Append(output);\n";
2066 }
2067
2068 geomHLSL += " \n"
2069 " outStream.RestartStrip();\n"
2070 "}\n";
2071
2072 return geomHLSL;
2073}
2074
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002075// This method needs to match OutputHLSL::decorate
2076std::string ProgramBinary::decorateAttribute(const std::string &name)
2077{
2078 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2079 {
2080 return "_" + name;
2081 }
2082
2083 return name;
2084}
2085
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002086bool ProgramBinary::isValidated() const
2087{
2088 return mValidated;
2089}
2090
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002091void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002092{
2093 // Skip over inactive attributes
2094 unsigned int activeAttribute = 0;
2095 unsigned int attribute;
2096 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2097 {
2098 if (mLinkedAttribute[attribute].name.empty())
2099 {
2100 continue;
2101 }
2102
2103 if (activeAttribute == index)
2104 {
2105 break;
2106 }
2107
2108 activeAttribute++;
2109 }
2110
2111 if (bufsize > 0)
2112 {
2113 const char *string = mLinkedAttribute[attribute].name.c_str();
2114
2115 strncpy(name, string, bufsize);
2116 name[bufsize - 1] = '\0';
2117
2118 if (length)
2119 {
2120 *length = strlen(name);
2121 }
2122 }
2123
2124 *size = 1; // Always a single 'type' instance
2125
2126 *type = mLinkedAttribute[attribute].type;
2127}
2128
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002129GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130{
2131 int count = 0;
2132
2133 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2134 {
2135 if (!mLinkedAttribute[attributeIndex].name.empty())
2136 {
2137 count++;
2138 }
2139 }
2140
2141 return count;
2142}
2143
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002144GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002145{
2146 int maxLength = 0;
2147
2148 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2149 {
2150 if (!mLinkedAttribute[attributeIndex].name.empty())
2151 {
2152 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2153 }
2154 }
2155
2156 return maxLength;
2157}
2158
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002159void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002160{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002161 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002162
2163 if (bufsize > 0)
2164 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002165 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002166
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002167 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002168 {
2169 string += "[0]";
2170 }
2171
2172 strncpy(name, string.c_str(), bufsize);
2173 name[bufsize - 1] = '\0';
2174
2175 if (length)
2176 {
2177 *length = strlen(name);
2178 }
2179 }
2180
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002181 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002182
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002183 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002184}
2185
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002186GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002187{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002188 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002189}
2190
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002191GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002192{
2193 int maxLength = 0;
2194
2195 unsigned int numUniforms = mUniforms.size();
2196 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2197 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002198 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199 {
2200 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2201 if (mUniforms[uniformIndex]->isArray())
2202 {
2203 length += 3; // Counting in "[0]".
2204 }
2205 maxLength = std::max(length, maxLength);
2206 }
2207 }
2208
2209 return maxLength;
2210}
2211
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002212void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002213{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002214 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002215 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002216 {
2217 mValidated = false;
2218 }
2219 else
2220 {
2221 mValidated = true;
2222 }
2223}
2224
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002225bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002226{
2227 // if any two active samplers in a program are of different types, but refer to the same
2228 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2229 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2230
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002231 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002232 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002233
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002234 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002235 {
2236 textureUnitType[i] = TEXTURE_UNKNOWN;
2237 }
2238
2239 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2240 {
2241 if (mSamplersPS[i].active)
2242 {
2243 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2244
2245 if (unit >= maxCombinedTextureImageUnits)
2246 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002247 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002248 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002249 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002250 }
2251
2252 return false;
2253 }
2254
2255 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2256 {
2257 if (mSamplersPS[i].textureType != textureUnitType[unit])
2258 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002259 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002260 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002261 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002262 }
2263
2264 return false;
2265 }
2266 }
2267 else
2268 {
2269 textureUnitType[unit] = mSamplersPS[i].textureType;
2270 }
2271 }
2272 }
2273
2274 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2275 {
2276 if (mSamplersVS[i].active)
2277 {
2278 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2279
2280 if (unit >= maxCombinedTextureImageUnits)
2281 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002282 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002283 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002284 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002285 }
2286
2287 return false;
2288 }
2289
2290 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2291 {
2292 if (mSamplersVS[i].textureType != textureUnitType[unit])
2293 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002294 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002295 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002296 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002297 }
2298
2299 return false;
2300 }
2301 }
2302 else
2303 {
2304 textureUnitType[unit] = mSamplersVS[i].textureType;
2305 }
2306 }
2307 }
2308
2309 return true;
2310}
2311
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002312ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2313{
2314}
2315
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002316struct AttributeSorter
2317{
2318 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2319 : originalIndices(semanticIndices)
2320 {
2321 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2322 {
2323 indices[i] = i;
2324 }
2325
2326 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2327 }
2328
2329 bool operator()(int a, int b)
2330 {
2331 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2332 }
2333
2334 int indices[MAX_VERTEX_ATTRIBS];
2335 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2336};
2337
2338void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2339{
2340 AttributeSorter sorter(mSemanticIndex);
2341
2342 int oldIndices[MAX_VERTEX_ATTRIBS];
2343 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2344
2345 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2346 {
2347 oldIndices[i] = mSemanticIndex[i];
2348 oldTranslatedAttributes[i] = attributes[i];
2349 }
2350
2351 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2352 {
2353 int oldIndex = sorter.indices[i];
2354 sortedSemanticIndices[i] = oldIndices[oldIndex];
2355 attributes[i] = oldTranslatedAttributes[oldIndex];
2356 }
2357}
2358
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002359}