blob: 005e3199832cf078cc94aebf88b23fd705b91540 [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"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/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"
Nicolas Capense6050882013-07-08 10:43:10 -040024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
Geoff Lang17732822013-08-29 13:46:49 -040027#include "compiler/translator/HLSLLayoutEncoder.h"
Jamie Madillc2141fb2013-08-30 13:21:08 -040028
daniel@transgaming.com88853c52012-12-20 20:56:40 +000029#undef near
30#undef far
31
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032namespace gl
33{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000034std::string str(int i)
35{
36 char buffer[20];
37 snprintf(buffer, sizeof(buffer), "%d", i);
38 return buffer;
39}
40
Jamie Madill63491ea2013-06-06 11:56:45 -040041std::string arrayString(int i)
42{
43 return "[" + str(i) + "]";
44}
45
Jamie Madill46131a32013-06-20 11:55:50 -040046std::string arrayString(unsigned int i)
47{
48 return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
49}
50
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000051namespace gl_d3d
52{
53 std::string TypeString(GLenum type)
54 {
55 switch (type)
56 {
57 case GL_FLOAT: return "float";
58 case GL_FLOAT_VEC2: return "float2";
59 case GL_FLOAT_VEC3: return "float3";
60 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000061 case GL_INT: return "int";
62 case GL_INT_VEC2: return "int2";
63 case GL_INT_VEC3: return "int3";
64 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000065 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000066 case GL_UNSIGNED_INT_VEC2: return "uint2";
67 case GL_UNSIGNED_INT_VEC3: return "uint3";
68 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000069 case GL_FLOAT_MAT2: return "float2x2";
70 case GL_FLOAT_MAT3: return "float3x3";
71 case GL_FLOAT_MAT4: return "float4x4";
72 case GL_FLOAT_MAT2x3: return "float2x3";
73 case GL_FLOAT_MAT3x2: return "float3x2";
74 case GL_FLOAT_MAT2x4: return "float2x4";
75 case GL_FLOAT_MAT4x2: return "float4x2";
76 case GL_FLOAT_MAT3x4: return "float3x4";
77 case GL_FLOAT_MAT4x3: return "float4x3";
78 default: UNREACHABLE(); return "invalid-gl-type";
79 }
80 }
81}
82
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000083namespace
84{
85
86unsigned int parseAndStripArrayIndex(std::string* name)
87{
88 unsigned int subscript = GL_INVALID_INDEX;
89
90 // Strip any trailing array operator and retrieve the subscript
91 size_t open = name->find_last_of('[');
92 size_t close = name->find_last_of(']');
93 if (open != std::string::npos && close == name->length() - 1)
94 {
95 subscript = atoi(name->substr(open + 1).c_str());
96 name->erase(open);
97 }
98
99 return subscript;
100}
101
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500102static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard)
103{
104 return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE);
105}
106
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000107}
108
Jamie Madill63491ea2013-06-06 11:56:45 -0400109VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000110 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000111{
112}
113
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000114unsigned int ProgramBinary::mCurrentSerial = 1;
115
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000116ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000117{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118 mPixelExecutable = NULL;
119 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000120 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000121
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000122 mValidated = false;
123
124 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
125 {
126 mSemanticIndex[index] = -1;
127 }
128
129 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
130 {
131 mSamplersPS[index].active = false;
132 }
133
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000134 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135 {
136 mSamplersVS[index].active = false;
137 }
138
139 mUsedVertexSamplerRange = 0;
140 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000141 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000142 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000143}
144
145ProgramBinary::~ProgramBinary()
146{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000147 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000148 mPixelExecutable = NULL;
149
daniel@transgaming.com95892412012-11-28 20:59:09 +0000150 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000151 mVertexExecutable = NULL;
152
153 delete mGeometryExecutable;
154 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000155
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000156 while (!mUniforms.empty())
157 {
158 delete mUniforms.back();
159 mUniforms.pop_back();
160 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000161
162 while (!mUniformBlocks.empty())
163 {
164 delete mUniformBlocks.back();
165 mUniformBlocks.pop_back();
166 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000167}
168
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000169unsigned int ProgramBinary::getSerial() const
170{
171 return mSerial;
172}
173
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000174int ProgramBinary::getShaderVersion() const
175{
176 return mShaderVersion;
177}
178
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000179unsigned int ProgramBinary::issueSerial()
180{
181 return mCurrentSerial++;
182}
183
daniel@transgaming.com95892412012-11-28 20:59:09 +0000184rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000185{
186 return mPixelExecutable;
187}
188
daniel@transgaming.com95892412012-11-28 20:59:09 +0000189rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000190{
191 return mVertexExecutable;
192}
193
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000194rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
195{
196 return mGeometryExecutable;
197}
198
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000199GLuint ProgramBinary::getAttributeLocation(const char *name)
200{
201 if (name)
202 {
203 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
204 {
205 if (mLinkedAttribute[index].name == std::string(name))
206 {
207 return index;
208 }
209 }
210 }
211
212 return -1;
213}
214
215int ProgramBinary::getSemanticIndex(int attributeIndex)
216{
217 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
218
219 return mSemanticIndex[attributeIndex];
220}
221
222// Returns one more than the highest sampler index used.
223GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
224{
225 switch (type)
226 {
227 case SAMPLER_PIXEL:
228 return mUsedPixelSamplerRange;
229 case SAMPLER_VERTEX:
230 return mUsedVertexSamplerRange;
231 default:
232 UNREACHABLE();
233 return 0;
234 }
235}
236
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000237bool ProgramBinary::usesPointSize() const
238{
239 return mUsesPointSize;
240}
241
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000242bool ProgramBinary::usesPointSpriteEmulation() const
243{
244 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
245}
246
247bool ProgramBinary::usesGeometryShader() const
248{
249 return usesPointSpriteEmulation();
250}
251
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000252// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
253// index (0-15 for the pixel shader and 0-3 for the vertex shader).
254GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
255{
256 GLint logicalTextureUnit = -1;
257
258 switch (type)
259 {
260 case SAMPLER_PIXEL:
261 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
262
263 if (mSamplersPS[samplerIndex].active)
264 {
265 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
266 }
267 break;
268 case SAMPLER_VERTEX:
269 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
270
271 if (mSamplersVS[samplerIndex].active)
272 {
273 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
274 }
275 break;
276 default: UNREACHABLE();
277 }
278
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000279 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000280 {
281 return logicalTextureUnit;
282 }
283
284 return -1;
285}
286
287// Returns the texture type for a given Direct3D 9 sampler type and
288// index (0-15 for the pixel shader and 0-3 for the vertex shader).
289TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
290{
291 switch (type)
292 {
293 case SAMPLER_PIXEL:
294 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
295 ASSERT(mSamplersPS[samplerIndex].active);
296 return mSamplersPS[samplerIndex].textureType;
297 case SAMPLER_VERTEX:
298 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
299 ASSERT(mSamplersVS[samplerIndex].active);
300 return mSamplersVS[samplerIndex].textureType;
301 default: UNREACHABLE();
302 }
303
304 return TEXTURE_2D;
305}
306
307GLint ProgramBinary::getUniformLocation(std::string name)
308{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000309 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000310
311 unsigned int numUniforms = mUniformIndex.size();
312 for (unsigned int location = 0; location < numUniforms; location++)
313 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000314 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000315 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000316 const int index = mUniformIndex[location].index;
317 const bool isArray = mUniforms[index]->isArray();
318
319 if ((isArray && mUniformIndex[location].element == subscript) ||
320 (subscript == GL_INVALID_INDEX))
321 {
322 return location;
323 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000324 }
325 }
326
327 return -1;
328}
329
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000330GLuint ProgramBinary::getUniformIndex(std::string name)
331{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000332 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000333
334 // The app is not allowed to specify array indices other than 0 for arrays of basic types
335 if (subscript != 0 && subscript != GL_INVALID_INDEX)
336 {
337 return GL_INVALID_INDEX;
338 }
339
340 unsigned int numUniforms = mUniforms.size();
341 for (unsigned int index = 0; index < numUniforms; index++)
342 {
343 if (mUniforms[index]->name == name)
344 {
345 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
346 {
347 return index;
348 }
349 }
350 }
351
352 return GL_INVALID_INDEX;
353}
354
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000355GLuint ProgramBinary::getUniformBlockIndex(std::string name)
356{
357 unsigned int subscript = parseAndStripArrayIndex(&name);
358
359 unsigned int numUniformBlocks = mUniformBlocks.size();
360 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
361 {
362 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
363 if (uniformBlock.name == name)
364 {
365 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
366 if (subscript == uniformBlock.elementIndex || arrayElementZero)
367 {
368 return blockIndex;
369 }
370 }
371 }
372
373 return GL_INVALID_INDEX;
374}
375
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000376UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
377{
378 ASSERT(blockIndex < mUniformBlocks.size());
379 return mUniformBlocks[blockIndex];
380}
381
Jamie Madilld1e78c92013-06-20 11:55:50 -0400382GLint ProgramBinary::getFragDataLocation(const char *name) const
383{
384 std::string baseName(name);
385 unsigned int arrayIndex;
386 arrayIndex = parseAndStripArrayIndex(&baseName);
387
388 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
389 {
390 const VariableLocation &outputVariable = locationIt->second;
391
392 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
393 {
394 return static_cast<GLint>(locationIt->first);
395 }
396 }
397
398 return -1;
399}
400
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000401template <typename T>
402bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000403{
404 if (location < 0 || location >= (int)mUniformIndex.size())
405 {
406 return false;
407 }
408
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000409 const int components = UniformComponentCount(targetUniformType);
410 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
411
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
413 targetUniform->dirty = true;
414
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000415 int elementCount = targetUniform->elementCount();
416
417 if (elementCount == 1 && count > 1)
418 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
419
420 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
421
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000422 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000423 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000424 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000425
426 for (int i = 0; i < count; i++)
427 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000428 for (int c = 0; c < components; c++)
429 {
430 target[c] = v[c];
431 }
432 for (int c = components; c < 4; c++)
433 {
434 target[c] = 0;
435 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000436 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000437 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438 }
439 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000440 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000441 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000442 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000443
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000444 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000446 for (int c = 0; c < components; c++)
447 {
448 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
449 }
450 for (int c = components; c < 4; c++)
451 {
452 boolParams[c] = GL_FALSE;
453 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000454 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000455 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000456 }
457 }
458 else
459 {
460 return false;
461 }
462
463 return true;
464}
465
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000466bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
467{
468 return setUniform(location, count, v, GL_FLOAT);
469}
470
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000471bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
472{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000473 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000474}
475
476bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
477{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000478 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000479}
480
481bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
482{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000483 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000484}
485
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000486template<typename T>
487void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000488{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000489 int copyWidth = std::min(targetHeight, srcWidth);
490 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000491
492 for (int x = 0; x < copyWidth; x++)
493 {
494 for (int y = 0; y < copyHeight; y++)
495 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000496 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000497 }
498 }
499 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000500 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000502 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000503 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000504 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000505 }
506 }
507 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000508 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000509 {
510 for (int x = 0; x < targetWidth; x++)
511 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000512 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000513 }
514 }
515}
516
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000517template<typename T>
518void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
519{
520 int copyWidth = std::min(targetWidth, srcWidth);
521 int copyHeight = std::min(targetHeight, srcHeight);
522
523 for (int y = 0; y < copyHeight; y++)
524 {
525 for (int x = 0; x < copyWidth; x++)
526 {
527 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
528 }
529 }
530 // clear unfilled right side
531 for (int y = 0; y < copyHeight; y++)
532 {
533 for (int x = copyWidth; x < targetWidth; x++)
534 {
535 target[y * targetWidth + x] = static_cast<T>(0);
536 }
537 }
538 // clear unfilled bottom.
539 for (int y = copyHeight; y < targetHeight; y++)
540 {
541 for (int x = 0; x < targetWidth; x++)
542 {
543 target[y * targetWidth + x] = static_cast<T>(0);
544 }
545 }
546}
547
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000548template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000549bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000550{
551 if (location < 0 || location >= (int)mUniformIndex.size())
552 {
553 return false;
554 }
555
556 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
557 targetUniform->dirty = true;
558
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000559 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560 {
561 return false;
562 }
563
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000564 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000565
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000566 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000567 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
568
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000569 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000570 const unsigned int targetMatrixStride = (4 * rows);
571 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000572
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000573 for (int i = 0; i < count; i++)
574 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000575 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
576 if (transpose == GL_FALSE)
577 {
578 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
579 }
580 else
581 {
582 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
583 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000584 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000585 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000586 }
587
588 return true;
589}
590
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000591bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000592{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000593 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000594}
595
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000596bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000597{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000598 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000599}
600
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000601bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000602{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000603 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000604}
605
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000606bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000607{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000608 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000609}
610
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000611bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000612{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000613 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000614}
615
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000616bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000617{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000618 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000619}
620
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000621bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000622{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000623 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000624}
625
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000626bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000627{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000628 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000629}
630
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000631bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000632{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000633 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000634}
635
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000636bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
637{
638 if (location < 0 || location >= (int)mUniformIndex.size())
639 {
640 return false;
641 }
642
643 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
644 targetUniform->dirty = true;
645
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000646 int elementCount = targetUniform->elementCount();
647
648 if (elementCount == 1 && count > 1)
649 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
650
651 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
652
Nicolas Capense6050882013-07-08 10:43:10 -0400653 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000655 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000656
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000657 for (int i = 0; i < count; i++)
658 {
659 target[0] = v[0];
660 target[1] = 0;
661 target[2] = 0;
662 target[3] = 0;
663 target += 4;
664 v += 1;
665 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000666 }
667 else if (targetUniform->type == GL_BOOL)
668 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000669 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000670
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000671 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000672 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000673 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
674 boolParams[1] = GL_FALSE;
675 boolParams[2] = GL_FALSE;
676 boolParams[3] = GL_FALSE;
677 boolParams += 4;
678 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000679 }
680 }
681 else
682 {
683 return false;
684 }
685
686 return true;
687}
688
689bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
690{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000691 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692}
693
694bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
695{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000696 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697}
698
699bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
700{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000701 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000702}
703
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000704bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
705{
706 return setUniform(location, count, v, GL_UNSIGNED_INT);
707}
708
709bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
710{
711 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
712}
713
714bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
715{
716 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
717}
718
719bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
720{
721 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
722}
723
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000724template <typename T>
725bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726{
727 if (location < 0 || location >= (int)mUniformIndex.size())
728 {
729 return false;
730 }
731
732 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
733
734 // sized queries -- ensure the provided buffer is large enough
735 if (bufSize)
736 {
737 int requiredBytes = UniformExternalSize(targetUniform->type);
738 if (*bufSize < requiredBytes)
739 {
740 return false;
741 }
742 }
743
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000744 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000745 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000746 const int rows = VariableRowCount(targetUniform->type);
747 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400748 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000749 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000750 else if (uniformType == UniformComponentType(targetUniform->type))
751 {
752 unsigned int size = UniformComponentCount(targetUniform->type);
753 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
754 size * sizeof(T));
755 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000756 else
757 {
758 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000759 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000760 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000761 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000762 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000763 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000764
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000765 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000766 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000767 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000768 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000769 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000770 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000771
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000772 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000773 {
774 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
775
776 for (unsigned int i = 0; i < size; i++)
777 {
778 params[i] = static_cast<T>(floatParams[i]);
779 }
780 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000781 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000782
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000783 case GL_INT:
784 {
785 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
786
787 for (unsigned int i = 0; i < size; i++)
788 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000789 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000790 }
791 }
792 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000793
794 case GL_UNSIGNED_INT:
795 {
796 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000797
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000798 for (unsigned int i = 0; i < size; i++)
799 {
800 params[i] = static_cast<T>(uintParams[i]);
801 }
802 }
803 break;
804
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000805 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000806 }
807 }
808
809 return true;
810}
811
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000812bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
813{
814 return getUniformv(location, bufSize, params, GL_FLOAT);
815}
816
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000817bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
818{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000819 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000820}
821
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000822bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
823{
824 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
825}
826
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000827void ProgramBinary::dirtyAllUniforms()
828{
829 unsigned int numUniforms = mUniforms.size();
830 for (unsigned int index = 0; index < numUniforms; index++)
831 {
832 mUniforms[index]->dirty = true;
833 }
834}
835
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000836// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000837void ProgramBinary::applyUniforms()
838{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000839 // Retrieve sampler uniform values
840 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
841 {
842 Uniform *targetUniform = *ub;
843
844 if (targetUniform->dirty)
845 {
Nicolas Capense6050882013-07-08 10:43:10 -0400846 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000847 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000848 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000849 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000850
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000851 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000852 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000853 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000854
855 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000856 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000857 unsigned int samplerIndex = firstIndex + i;
858
859 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000860 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000861 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000862 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000863 }
864 }
865 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000866
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000867 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000868 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000869 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000870
871 for (int i = 0; i < count; i++)
872 {
873 unsigned int samplerIndex = firstIndex + i;
874
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000875 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000876 {
877 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000878 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000879 }
880 }
881 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000882 }
883 }
884 }
885
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000886 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000887}
888
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000889bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
890{
891 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
892 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
893
894 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
895 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
896
897 ASSERT(boundBuffers.size() == mUniformBlocks.size());
898
899 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
900 {
901 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
902 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
903
904 ASSERT(uniformBlock && uniformBuffer);
905
906 if (uniformBuffer->size() < uniformBlock->dataSize)
907 {
908 // undefined behaviour
909 return false;
910 }
911
912 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
913
914 if (uniformBlock->isReferencedByVertexShader())
915 {
916 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
917 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
918 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
919 vertexUniformBuffers[registerIndex] = uniformBuffer;
920 }
921
922 if (uniformBlock->isReferencedByFragmentShader())
923 {
924 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
925 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
926 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
927 fragmentUniformBuffers[registerIndex] = uniformBuffer;
928 }
929 }
930
931 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
932}
933
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000934// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
935// Returns the number of used varying registers, or -1 if unsuccesful
Jamie Madilla6da33a2013-08-30 13:21:07 -0400936int ProgramBinary::packVaryings(InfoLog &infoLog, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000937{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000938 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000939
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000940 fragmentShader->resetVaryingsRegisterAssignment();
941
Jamie Madillce79dda2013-08-30 13:21:06 -0400942 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000943 {
Jamie Madilla6da33a2013-08-30 13:21:07 -0400944 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000945 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -0400946
947 // matrices within varying structs are not transposed
948 int registers = (varying->isStruct() ? sh::HLSLVariableRegisterCount(*varying) : gl::VariableRowCount(transposedType)) * varying->elementCount();
949 int elements = (varying->isStruct() ? 4 : VariableColumnCount(transposedType));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000950 bool success = false;
951
Jamie Madill28167c62013-08-30 13:21:10 -0400952 if (elements == 2 || elements == 3 || elements == 4)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000953 {
Jamie Madill28167c62013-08-30 13:21:10 -0400954 for (int r = 0; r <= maxVaryingVectors - registers && !success; r++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000955 {
956 bool available = true;
957
Jamie Madill28167c62013-08-30 13:21:10 -0400958 for (int y = 0; y < registers && available; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000959 {
Jamie Madill28167c62013-08-30 13:21:10 -0400960 for (int x = 0; x < elements && available; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000961 {
962 if (packing[r + y][x])
963 {
964 available = false;
965 }
966 }
967 }
968
969 if (available)
970 {
Jamie Madill139b9092013-08-30 13:21:06 -0400971 varying->registerIndex = r;
972 varying->elementIndex = 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000973
Jamie Madill28167c62013-08-30 13:21:10 -0400974 for (int y = 0; y < registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000975 {
Jamie Madill28167c62013-08-30 13:21:10 -0400976 for (int x = 0; x < elements; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000977 {
978 packing[r + y][x] = &*varying;
979 }
980 }
981
982 success = true;
983 }
984 }
985
Jamie Madill28167c62013-08-30 13:21:10 -0400986 if (!success && elements == 2)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000987 {
Jamie Madill28167c62013-08-30 13:21:10 -0400988 for (int r = maxVaryingVectors - registers; r >= 0 && !success; r--)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000989 {
990 bool available = true;
991
Jamie Madill28167c62013-08-30 13:21:10 -0400992 for (int y = 0; y < registers && available; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000993 {
994 for (int x = 2; x < 4 && available; x++)
995 {
996 if (packing[r + y][x])
997 {
998 available = false;
999 }
1000 }
1001 }
1002
1003 if (available)
1004 {
Jamie Madill139b9092013-08-30 13:21:06 -04001005 varying->registerIndex = r;
1006 varying->elementIndex = 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001007
Jamie Madill28167c62013-08-30 13:21:10 -04001008 for (int y = 0; y < registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001009 {
1010 for (int x = 2; x < 4; x++)
1011 {
1012 packing[r + y][x] = &*varying;
1013 }
1014 }
1015
1016 success = true;
1017 }
1018 }
1019 }
1020 }
Jamie Madill28167c62013-08-30 13:21:10 -04001021 else if (elements == 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001022 {
1023 int space[4] = {0};
1024
1025 for (int y = 0; y < maxVaryingVectors; y++)
1026 {
1027 for (int x = 0; x < 4; x++)
1028 {
1029 space[x] += packing[y][x] ? 0 : 1;
1030 }
1031 }
1032
1033 int column = 0;
1034
1035 for (int x = 0; x < 4; x++)
1036 {
Jamie Madill28167c62013-08-30 13:21:10 -04001037 if (space[x] >= registers && space[x] < space[column])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001038 {
1039 column = x;
1040 }
1041 }
1042
Jamie Madill28167c62013-08-30 13:21:10 -04001043 if (space[column] >= registers)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044 {
1045 for (int r = 0; r < maxVaryingVectors; r++)
1046 {
1047 if (!packing[r][column])
1048 {
Jamie Madill139b9092013-08-30 13:21:06 -04001049 varying->registerIndex = r;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001050
Jamie Madill28167c62013-08-30 13:21:10 -04001051 for (int y = r; y < r + registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052 {
1053 packing[y][column] = &*varying;
1054 }
1055
1056 break;
1057 }
1058 }
1059
Jamie Madill139b9092013-08-30 13:21:06 -04001060 varying->elementIndex = column;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001061
1062 success = true;
1063 }
1064 }
1065 else UNREACHABLE();
1066
1067 if (!success)
1068 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001069 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001070
1071 return -1;
1072 }
1073 }
1074
1075 // Return the number of used registers
1076 int registers = 0;
1077
1078 for (int r = 0; r < maxVaryingVectors; r++)
1079 {
1080 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1081 {
1082 registers++;
1083 }
1084 }
1085
1086 return registers;
1087}
1088
Jamie Madill46131a32013-06-20 11:55:50 -04001089void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1090{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001091 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001092
1093 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1094 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001095 const sh::Attribute &outputVariable = outputVars[outputVariableIndex];
Jamie Madill46131a32013-06-20 11:55:50 -04001096 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1097
1098 if (outputVariable.arraySize > 0)
1099 {
1100 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1101 {
1102 const int location = baseLocation + elementIndex;
1103 ASSERT(mOutputVariables.count(location) == 0);
1104 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1105 }
1106 }
1107 else
1108 {
1109 ASSERT(mOutputVariables.count(baseLocation) == 0);
1110 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1111 }
1112 }
1113}
1114
Jamie Madilla6da33a2013-08-30 13:21:07 -04001115bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const sh::ShaderVariable *packing[][4],
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001116 std::string& pixelHLSL, std::string& vertexHLSL,
1117 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001118{
1119 if (pixelHLSL.empty() || vertexHLSL.empty())
1120 {
1121 return false;
1122 }
1123
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001124 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1125 bool usesFragColor = fragmentShader->mUsesFragColor;
1126 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001127 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001128 {
1129 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1130 return false;
1131 }
1132
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001133 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001134 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001135 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001136
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001137 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1138
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001139 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1140 // - with a 3.0 context, the output color is copied to channel 0
1141 // - with a 2.0 context, the output color is broadcast to all channels
1142 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1143 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1144
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001145 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001146 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001147 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001148
1149 return false;
1150 }
1151
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001152 vertexShader->resetVaryingsRegisterAssignment();
1153
Jamie Madillce79dda2013-08-30 13:21:06 -04001154 for (unsigned int fragVaryingIndex = 0; fragVaryingIndex < fragmentShader->mVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001156 sh::Varying *input = &fragmentShader->mVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001157 bool matched = false;
1158
Jamie Madillce79dda2013-08-30 13:21:06 -04001159 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001160 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001161 sh::Varying *output = &vertexShader->mVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001162 if (output->name == input->name)
1163 {
Jamie Madill28167c62013-08-30 13:21:10 -04001164 if (!linkValidateVariables(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001165 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001166 return false;
1167 }
1168
Jamie Madill139b9092013-08-30 13:21:06 -04001169 output->registerIndex = input->registerIndex;
1170 output->elementIndex = input->elementIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001171
1172 matched = true;
1173 break;
1174 }
1175 }
1176
1177 if (!matched)
1178 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001179 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001180
1181 return false;
1182 }
1183 }
1184
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001185 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001186 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001187 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001188 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001189 std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001190
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001191 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1192
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001193 // special varyings that use reserved registers
1194 int reservedRegisterIndex = registers;
1195 std::string fragCoordSemantic;
1196 std::string pointCoordSemantic;
1197
1198 if (fragmentShader->mUsesFragCoord)
1199 {
1200 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1201 }
1202
1203 if (fragmentShader->mUsesPointCoord)
1204 {
1205 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1206 // In DX11 we compute this in the GS.
1207 if (shaderModel == 3)
1208 {
1209 pointCoordSemantic = "TEXCOORD0";
1210 }
1211 else if (shaderModel >= 4)
1212 {
1213 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1214 }
1215 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001216
1217 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001218 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001219
1220 int semanticIndex = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001221 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
Jamie Madilldefb6742013-06-20 11:55:51 -04001222 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001223 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001224 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilldefb6742013-06-20 11:55:51 -04001225 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1226 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001227
Jamie Madilldefb6742013-06-20 11:55:51 -04001228 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001229 }
1230
1231 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001232 "\n"
1233 "struct VS_OUTPUT\n"
1234 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001235
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001236 if (shaderModel < 4)
1237 {
1238 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1239 }
1240
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001241 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 if (fragmentShader->mUsesFragCoord)
1244 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001245 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001246 }
1247
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001248 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001249 {
1250 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1251 }
1252
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001253 if (shaderModel >= 4)
1254 {
1255 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1256 }
1257
1258 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001259 "\n"
1260 "VS_OUTPUT main(VS_INPUT input)\n"
1261 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262
Jamie Madilldefb6742013-06-20 11:55:51 -04001263 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001264 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001265 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1266 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001267
Jamie Madilldefb6742013-06-20 11:55:51 -04001268 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001269 {
1270 vertexHLSL += "transpose";
1271 }
1272
Jamie Madilldefb6742013-06-20 11:55:51 -04001273 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001274 }
1275
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001276 if (shaderModel >= 4)
1277 {
1278 vertexHLSL += "\n"
1279 " gl_main();\n"
1280 "\n"
1281 " VS_OUTPUT output;\n"
1282 " output.gl_Position.x = gl_Position.x;\n"
1283 " output.gl_Position.y = -gl_Position.y;\n"
1284 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1285 " output.gl_Position.w = gl_Position.w;\n";
1286 }
1287 else
1288 {
1289 vertexHLSL += "\n"
1290 " gl_main();\n"
1291 "\n"
1292 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001293 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1294 " 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 +00001295 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1296 " output.gl_Position.w = gl_Position.w;\n";
1297 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001299 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001300 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001301 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001302 }
1303
1304 if (fragmentShader->mUsesFragCoord)
1305 {
1306 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1307 }
1308
Jamie Madillce79dda2013-08-30 13:21:06 -04001309 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001311 sh::Varying *varying = &vertexShader->mVaryings[vertVaryingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001312 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001313 {
Jamie Madill139b9092013-08-30 13:21:06 -04001314 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001315 {
Jamie Madill28167c62013-08-30 13:21:10 -04001316 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying->type)));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001317
Jamie Madill139b9092013-08-30 13:21:06 -04001318 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001319 {
Jamie Madill139b9092013-08-30 13:21:06 -04001320 int r = varying->registerIndex + elementIndex * variableRows + row;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001321 vertexHLSL += " output.v" + str(r);
1322
1323 bool sharedRegister = false; // Register used by multiple varyings
1324
1325 for (int x = 0; x < 4; x++)
1326 {
1327 if (packing[r][x] && packing[r][x] != packing[r][0])
1328 {
1329 sharedRegister = true;
1330 break;
1331 }
1332 }
1333
1334 if(sharedRegister)
1335 {
1336 vertexHLSL += ".";
1337
1338 for (int x = 0; x < 4; x++)
1339 {
1340 if (packing[r][x] == &*varying)
1341 {
1342 switch(x)
1343 {
1344 case 0: vertexHLSL += "x"; break;
1345 case 1: vertexHLSL += "y"; break;
1346 case 2: vertexHLSL += "z"; break;
1347 case 3: vertexHLSL += "w"; break;
1348 }
1349 }
1350 }
1351 }
1352
Jamie Madill139b9092013-08-30 13:21:06 -04001353 vertexHLSL += " = _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001354
Jamie Madill139b9092013-08-30 13:21:06 -04001355 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001356 {
Jamie Madill139b9092013-08-30 13:21:06 -04001357 vertexHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358 }
1359
Jamie Madill139b9092013-08-30 13:21:06 -04001360 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001361 {
Jamie Madill139b9092013-08-30 13:21:06 -04001362 vertexHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001363 }
1364
1365 vertexHLSL += ";\n";
1366 }
1367 }
1368 }
1369 }
1370
1371 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001372 " return output;\n"
1373 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001374
1375 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001376 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001377
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001378 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001379
1380 if (fragmentShader->mUsesFragCoord)
1381 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001382 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001383 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001384
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001385 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1386 {
1387 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1388 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001389
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001390 // Must consume the PSIZE element if the geometry shader is not active
1391 // We won't know if we use a GS until we draw
1392 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1393 {
1394 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1395 }
1396
1397 if (fragmentShader->mUsesFragCoord)
1398 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001399 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001400 {
1401 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1402 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001403 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001404 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001405 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1406 }
1407 }
1408
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001409 pixelHLSL += "};\n"
1410 "\n"
1411 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001412 "{\n";
1413
Jamie Madill46131a32013-06-20 11:55:50 -04001414 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001415 {
Jamie Madill46131a32013-06-20 11:55:50 -04001416 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1417 {
1418 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1419 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001420
1421 if (fragmentShader->mUsesFragDepth)
1422 {
1423 pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
1424 }
Jamie Madill46131a32013-06-20 11:55:50 -04001425 }
1426 else
1427 {
1428 defineOutputVariables(fragmentShader);
1429
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001430 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001431 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1432 {
1433 const VariableLocation &outputLocation = locationIt->second;
1434 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1435 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1436
1437 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1438 " out_" + outputLocation.name + elementString +
1439 " : " + targetSemantic + str(locationIt->first) + ";\n";
1440 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001441 }
1442
1443 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001444 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001445
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001446 if (fragmentShader->mUsesFrontFacing)
1447 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001448 if (shaderModel >= 4)
1449 {
1450 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1451 "{\n";
1452 }
1453 else
1454 {
1455 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1456 "{\n";
1457 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001459 else
1460 {
1461 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1462 "{\n";
1463 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001464
1465 if (fragmentShader->mUsesFragCoord)
1466 {
1467 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1468
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001469 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001470 {
1471 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1472 " gl_FragCoord.y = input.dx_VPos.y;\n";
1473 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001474 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001475 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001476 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001477 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001478 }
1479 else
1480 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001481 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1482 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1483 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001484 }
1485
daniel@transgaming.com12985182012-12-20 20:56:31 +00001486 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001487 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001488 }
1489
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001490 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001491 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001492 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1493 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001494 }
1495
1496 if (fragmentShader->mUsesFrontFacing)
1497 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001498 if (shaderModel <= 3)
1499 {
1500 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1501 }
1502 else
1503 {
1504 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1505 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001506 }
1507
Jamie Madillce79dda2013-08-30 13:21:06 -04001508 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001509 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001510 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001511 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001512 {
Jamie Madill139b9092013-08-30 13:21:06 -04001513 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001514 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001515 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -04001516 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
Jamie Madill139b9092013-08-30 13:21:06 -04001517 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001518 {
Jamie Madill139b9092013-08-30 13:21:06 -04001519 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
1520 pixelHLSL += " _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001521
Jamie Madill139b9092013-08-30 13:21:06 -04001522 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001523 {
Jamie Madill139b9092013-08-30 13:21:06 -04001524 pixelHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001525 }
1526
Jamie Madill139b9092013-08-30 13:21:06 -04001527 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001528 {
Jamie Madill139b9092013-08-30 13:21:06 -04001529 pixelHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001530 }
1531
Jamie Madill28167c62013-08-30 13:21:10 -04001532 if (varying->isStruct())
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001533 {
Jamie Madill28167c62013-08-30 13:21:10 -04001534 pixelHLSL += " = input.v" + n + ";\n"; break;
1535 }
1536 else
1537 {
1538 switch (VariableColumnCount(transposedType))
1539 {
1540 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1541 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1542 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1543 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1544 default: UNREACHABLE();
1545 }
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001546 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001547 }
1548 }
1549 }
1550 else UNREACHABLE();
1551 }
1552
1553 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001554 " gl_main();\n"
1555 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001556 " PS_OUTPUT output;\n";
1557
Jamie Madill46131a32013-06-20 11:55:50 -04001558 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001559 {
Jamie Madill46131a32013-06-20 11:55:50 -04001560 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1561 {
1562 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001563
Jamie Madill46131a32013-06-20 11:55:50 -04001564 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1565 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001566
1567 if (fragmentShader->mUsesFragDepth)
1568 {
1569 pixelHLSL += " output.gl_Depth = gl_Depth;\n";
1570 }
Jamie Madill46131a32013-06-20 11:55:50 -04001571 }
1572 else
1573 {
1574 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1575 {
1576 const VariableLocation &outputLocation = locationIt->second;
1577 const std::string &variableName = "out_" + outputLocation.name;
1578 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1579 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1580
1581 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1582 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001583 }
1584
1585 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001586 " return output;\n"
1587 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001588
1589 return true;
1590}
1591
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001592std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1593{
1594 std::string varyingHLSL;
1595
Jamie Madillce79dda2013-08-30 13:21:06 -04001596 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001597 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001598 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001599 if (varying->registerAssigned())
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001600 {
Jamie Madill139b9092013-08-30 13:21:06 -04001601 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001602 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001603 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -04001604 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
Jamie Madill139b9092013-08-30 13:21:06 -04001605 for (int row = 0; row < variableRows; row++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001606 {
1607 switch (varying->interpolation)
1608 {
Jamie Madill139b9092013-08-30 13:21:06 -04001609 case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break;
1610 case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break;
1611 case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break;
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001612 default: UNREACHABLE();
1613 }
1614
Jamie Madill139b9092013-08-30 13:21:06 -04001615 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
Jamie Madill28167c62013-08-30 13:21:10 -04001616
1617 // matrices within structs are not transposed, hence we do not use the special struct prefix "rm"
1618 std::string typeString = varying->isStruct() ? "_" + varying->structName :
1619 gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001620
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001621 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001622 }
1623 }
1624 }
1625 else UNREACHABLE();
1626 }
1627
1628 return varyingHLSL;
1629}
1630
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1632{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001633 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634
1635 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001636 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001637 if (format != GL_PROGRAM_BINARY_ANGLE)
1638 {
1639 infoLog.append("Invalid program binary format.");
1640 return false;
1641 }
1642
Jamie Madill049108d2013-11-19 10:41:49 -05001643 int majorVersion = 0;
1644 int minorVersion = 0;
1645 stream.read(&majorVersion);
1646 stream.read(&minorVersion);
1647 if (majorVersion != MAJOR_VERSION || minorVersion != MINOR_VERSION)
1648 {
1649 infoLog.append("Invalid program binary version.");
1650 return false;
1651 }
1652
1653 unsigned char commitString[COMMIT_STRING_LEN];
1654 stream.read(commitString, COMMIT_STRING_LEN);
1655 if (memcmp(commitString, COMMIT_STRING, sizeof(unsigned char) * COMMIT_STRING_LEN) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656 {
1657 infoLog.append("Invalid program binary version.");
1658 return false;
1659 }
1660
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001661 int compileFlags = 0;
1662 stream.read(&compileFlags);
1663 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1664 {
1665 infoLog.append("Mismatched compilation flags.");
1666 return false;
1667 }
1668
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1670 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&name);
1674 mLinkedAttribute[i].name = name;
1675 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001676 }
1677
Al Patrick3f2daa82013-08-07 12:58:57 -07001678 initAttributesByLayout();
1679
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001680 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1681 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001682 stream.read(&mSamplersPS[i].active);
1683 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684
1685 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001686 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001687 mSamplersPS[i].textureType = (TextureType) textureType;
1688 }
1689
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001690 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001691 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001692 stream.read(&mSamplersVS[i].active);
1693 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001694
1695 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001696 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697 mSamplersVS[i].textureType = (TextureType) textureType;
1698 }
1699
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001700 stream.read(&mUsedVertexSamplerRange);
1701 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001702 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001703 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001705 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 stream.read(&size);
1707 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708 {
1709 infoLog.append("Invalid program binary.");
1710 return false;
1711 }
1712
1713 mUniforms.resize(size);
1714 for (unsigned int i = 0; i < size; ++i)
1715 {
1716 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001717 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001718 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001719 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001720 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001721
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001722 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001723 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001724 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001725 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001726 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001727
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001728 int offset;
1729 int arrayStride;
1730 int matrixStride;
1731 bool isRowMajorMatrix;
1732
1733 stream.read(&offset);
1734 stream.read(&arrayStride);
1735 stream.read(&matrixStride);
1736 stream.read(&isRowMajorMatrix);
1737
1738 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1739
1740 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001742 stream.read(&mUniforms[i]->psRegisterIndex);
1743 stream.read(&mUniforms[i]->vsRegisterIndex);
1744 stream.read(&mUniforms[i]->registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001745 stream.read(&mUniforms[i]->registerElement);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746 }
1747
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001748 stream.read(&size);
1749 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001750 {
1751 infoLog.append("Invalid program binary.");
1752 return false;
1753 }
1754
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001755 mUniformBlocks.resize(size);
1756 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1757 {
1758 std::string name;
1759 unsigned int elementIndex;
1760 unsigned int dataSize;
1761
1762 stream.read(&name);
1763 stream.read(&elementIndex);
1764 stream.read(&dataSize);
1765
1766 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1767
1768 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1769 stream.read(&uniformBlock.psRegisterIndex);
1770 stream.read(&uniformBlock.vsRegisterIndex);
1771
1772 size_t numMembers;
1773 stream.read(&numMembers);
1774 uniformBlock.memberUniformIndexes.resize(numMembers);
1775 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1776 {
1777 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1778 }
1779 }
1780
1781 stream.read(&size);
1782 if (stream.error())
1783 {
1784 infoLog.append("Invalid program binary.");
1785 return false;
1786 }
1787
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788 mUniformIndex.resize(size);
1789 for (unsigned int i = 0; i < size; ++i)
1790 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.read(&mUniformIndex[i].name);
1792 stream.read(&mUniformIndex[i].element);
1793 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794 }
1795
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001797 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001798
1799 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001800 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001802 unsigned int geometryShaderSize;
1803 stream.read(&geometryShaderSize);
1804
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001805 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001806
daniel@transgaming.com36038542012-11-28 20:59:26 +00001807 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 ptr += sizeof(GUID);
1809
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001810 GUID identifier = mRenderer->getAdapterIdentifier();
1811 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812 {
1813 infoLog.append("Invalid program binary.");
1814 return false;
1815 }
1816
1817 const char *pixelShaderFunction = ptr;
1818 ptr += pixelShaderSize;
1819
1820 const char *vertexShaderFunction = ptr;
1821 ptr += vertexShaderSize;
1822
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001823 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1824 ptr += geometryShaderSize;
1825
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001826 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001827 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001828 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 {
1830 infoLog.append("Could not create pixel shader.");
1831 return false;
1832 }
1833
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001834 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001835 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001836 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837 {
1838 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001839 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001840 mPixelExecutable = NULL;
1841 return false;
1842 }
1843
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001844 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1845 {
1846 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1847 geometryShaderSize, rx::SHADER_GEOMETRY);
1848 if (!mGeometryExecutable)
1849 {
1850 infoLog.append("Could not create geometry shader.");
1851 delete mPixelExecutable;
1852 mPixelExecutable = NULL;
1853 delete mVertexExecutable;
1854 mVertexExecutable = NULL;
1855 return false;
1856 }
1857 }
1858 else
1859 {
1860 mGeometryExecutable = NULL;
1861 }
1862
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001863 return true;
1864}
1865
1866bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1867{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001868 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001869
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001870 stream.write(GL_PROGRAM_BINARY_ANGLE);
Jamie Madill049108d2013-11-19 10:41:49 -05001871 stream.write(MAJOR_VERSION);
1872 stream.write(MINOR_VERSION);
1873 stream.write(COMMIT_STRING, COMMIT_STRING_LEN);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001874 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001875
1876 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1877 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001878 stream.write(mLinkedAttribute[i].type);
1879 stream.write(mLinkedAttribute[i].name);
1880 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001881 }
1882
1883 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1884 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001885 stream.write(mSamplersPS[i].active);
1886 stream.write(mSamplersPS[i].logicalTextureUnit);
1887 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001888 }
1889
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001890 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001891 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001892 stream.write(mSamplersVS[i].active);
1893 stream.write(mSamplersVS[i].logicalTextureUnit);
1894 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001895 }
1896
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001897 stream.write(mUsedVertexSamplerRange);
1898 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001899 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001900 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001901
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001902 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001903 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001904 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001905 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001906
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001907 stream.write(uniform.type);
1908 stream.write(uniform.precision);
1909 stream.write(uniform.name);
1910 stream.write(uniform.arraySize);
1911 stream.write(uniform.blockIndex);
1912
1913 stream.write(uniform.blockInfo.offset);
1914 stream.write(uniform.blockInfo.arrayStride);
1915 stream.write(uniform.blockInfo.matrixStride);
1916 stream.write(uniform.blockInfo.isRowMajorMatrix);
1917
1918 stream.write(uniform.psRegisterIndex);
1919 stream.write(uniform.vsRegisterIndex);
1920 stream.write(uniform.registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001921 stream.write(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001922 }
1923
1924 stream.write(mUniformBlocks.size());
1925 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1926 {
1927 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1928
1929 stream.write(uniformBlock.name);
1930 stream.write(uniformBlock.elementIndex);
1931 stream.write(uniformBlock.dataSize);
1932
1933 stream.write(uniformBlock.memberUniformIndexes.size());
1934 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1935 {
1936 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1937 }
1938
1939 stream.write(uniformBlock.psRegisterIndex);
1940 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001941 }
1942
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001943 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001944 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1945 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001946 stream.write(mUniformIndex[i].name);
1947 stream.write(mUniformIndex[i].element);
1948 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001949 }
1950
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001951 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001952 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001953
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001954 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001955 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001956
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001957 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1958 stream.write(geometryShaderSize);
1959
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001960 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001961
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001962 GLsizei streamLength = stream.length();
1963 const void *streamData = stream.data();
1964
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001965 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001966 if (totalLength > bufSize)
1967 {
1968 if (length)
1969 {
1970 *length = 0;
1971 }
1972
1973 return false;
1974 }
1975
1976 if (binary)
1977 {
1978 char *ptr = (char*) binary;
1979
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001980 memcpy(ptr, streamData, streamLength);
1981 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001982
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001983 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001984 ptr += sizeof(GUID);
1985
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001986 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001987 ptr += pixelShaderSize;
1988
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001989 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001990 ptr += vertexShaderSize;
1991
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001992 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1993 {
1994 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1995 ptr += geometryShaderSize;
1996 }
1997
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001998 ASSERT(ptr - totalLength == binary);
1999 }
2000
2001 if (length)
2002 {
2003 *length = totalLength;
2004 }
2005
2006 return true;
2007}
2008
2009GLint ProgramBinary::getLength()
2010{
2011 GLint length;
2012 if (save(NULL, INT_MAX, &length))
2013 {
2014 return length;
2015 }
2016 else
2017 {
2018 return 0;
2019 }
2020}
2021
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002022bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002023{
2024 if (!fragmentShader || !fragmentShader->isCompiled())
2025 {
2026 return false;
2027 }
2028
2029 if (!vertexShader || !vertexShader->isCompiled())
2030 {
2031 return false;
2032 }
2033
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00002034 mShaderVersion = vertexShader->getShaderVersion();
2035
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002036 std::string pixelHLSL = fragmentShader->getHLSL();
2037 std::string vertexHLSL = vertexShader->getHLSL();
2038
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002039 // Map the varyings to the register file
Jamie Madilla6da33a2013-08-30 13:21:07 -04002040 const sh::ShaderVariable *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002041 int registers = packVaryings(infoLog, packing, fragmentShader);
2042
2043 if (registers < 0)
2044 {
2045 return false;
2046 }
2047
2048 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002049 {
2050 return false;
2051 }
2052
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002053 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002054
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002055 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2056 {
2057 success = false;
2058 }
2059
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002060 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002061 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002062 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002063 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002064
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002065 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2066 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2067 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002068 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2069 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2070 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002071 }
2072
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002073 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2074 {
2075 success = false;
2076 }
2077
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002078 if (success)
2079 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002080 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting));
2081 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting));
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002082
2083 if (usesGeometryShader())
2084 {
2085 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002086 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002087 }
2088
2089 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
2090 {
2091 infoLog.append("Failed to create D3D shaders.");
2092 success = false;
2093
2094 delete mVertexExecutable;
2095 mVertexExecutable = NULL;
2096 delete mPixelExecutable;
2097 mPixelExecutable = NULL;
2098 delete mGeometryExecutable;
2099 mGeometryExecutable = NULL;
2100 }
2101 }
2102
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002103 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104}
2105
2106// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002107bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002108{
2109 unsigned int usedLocations = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002110 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111
2112 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002113 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002114 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002115 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002116 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002117
Jamie Madilleba4eff2013-06-20 11:55:51 -04002118 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002119 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002120 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121
2122 if (rows + location > MAX_VERTEX_ATTRIBS)
2123 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002124 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 +00002125
2126 return false;
2127 }
2128
Jamie Madilleba4eff2013-06-20 11:55:51 -04002129 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002131 const int rowLocation = location + row;
2132 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2133
2134 // In GLSL 3.00, attribute aliasing produces a link error
2135 // In GLSL 1.00, attribute aliasing is allowed
2136 if (mShaderVersion >= 300)
2137 {
2138 if (!linkedAttribute.name.empty())
2139 {
2140 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2141 return false;
2142 }
2143 }
2144
2145 linkedAttribute = attribute;
2146 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002147 }
2148 }
2149 }
2150
2151 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002152 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002153 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002154 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002155 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002156
Jamie Madilleba4eff2013-06-20 11:55:51 -04002157 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002158 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002159 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002160 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2161
2162 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2163 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002164 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002165
2166 return false; // Fail to link
2167 }
2168
Jamie Madilldefb6742013-06-20 11:55:51 -04002169 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002170 }
2171 }
2172
2173 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2174 {
2175 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002176 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002177
2178 for (int r = 0; r < rows; r++)
2179 {
2180 mSemanticIndex[attributeIndex++] = index++;
2181 }
2182 }
2183
Al Patrick3f2daa82013-08-07 12:58:57 -07002184 initAttributesByLayout();
2185
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002186 return true;
2187}
2188
Jamie Madill28167c62013-08-30 13:21:10 -04002189bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002190{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002191 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002192 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002193 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002194 return false;
2195 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002196 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002197 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002198 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002199 return false;
2200 }
Jamie Madill28167c62013-08-30 13:21:10 -04002201 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002202 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002203 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04002204 return false;
2205 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002206
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002207 return true;
2208}
2209
2210template <class ShaderVarType>
2211bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
2212{
2213 if (vertexVar.fields.size() != fragmentVar.fields.size())
2214 {
2215 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
2216 return false;
2217 }
2218 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002219 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2220 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002221 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
2222 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002223
2224 if (vertexMember.name != fragmentMember.name)
2225 {
Jamie Madill28167c62013-08-30 13:21:10 -04002226 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
2227 memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002228 return false;
2229 }
2230
Jamie Madill28167c62013-08-30 13:21:10 -04002231 const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002232 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002233 {
2234 return false;
2235 }
2236 }
2237
2238 return true;
2239}
2240
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002241bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2242{
Jamie Madill28167c62013-08-30 13:21:10 -04002243 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002244 {
2245 return false;
2246 }
2247
2248 if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
2249 {
2250 return false;
2251 }
2252
2253 return true;
2254}
2255
Jamie Madill28167c62013-08-30 13:21:10 -04002256bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
2257{
2258 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2259 {
2260 return false;
2261 }
2262
2263 if (vertexVarying.interpolation != fragmentVarying.interpolation)
2264 {
2265 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
2266 return false;
2267 }
2268
2269 if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
2270 {
2271 return false;
2272 }
2273
2274 return true;
2275}
2276
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002277bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
2278{
Jamie Madill28167c62013-08-30 13:21:10 -04002279 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002280 {
2281 return false;
2282 }
2283
2284 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2285 {
2286 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2287 return false;
2288 }
2289
2290 if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
2291 {
2292 return false;
2293 }
2294
2295 return true;
2296}
2297
2298bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002299{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002300 // Check that uniforms defined in the vertex and fragment shaders are identical
2301 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2302 UniformMap linkedUniforms;
2303
2304 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2305 {
2306 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2307 linkedUniforms[vertexUniform.name] = &vertexUniform;
2308 }
2309
2310 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2311 {
2312 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2313 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2314 if (entry != linkedUniforms.end())
2315 {
2316 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04002317 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002318 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002319 {
2320 return false;
2321 }
2322 }
2323 }
2324
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002325 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002326 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002327 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002328 {
2329 return false;
2330 }
2331 }
2332
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002333 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002334 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002335 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002336 {
2337 return false;
2338 }
2339 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002340
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002341 return true;
2342}
2343
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002344int totalRegisterCount(const sh::Uniform &uniform)
2345{
2346 int registerCount = 0;
2347
2348 if (!uniform.fields.empty())
2349 {
2350 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2351 {
2352 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2353 }
2354 }
2355 else
2356 {
2357 registerCount = 1;
2358 }
2359
2360 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2361}
2362
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002363TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
2364{
2365 switch(samplerType)
2366 {
2367 case GL_SAMPLER_2D:
2368 case GL_INT_SAMPLER_2D:
2369 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002370 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002371 return TEXTURE_2D;
2372 case GL_SAMPLER_3D:
2373 case GL_INT_SAMPLER_3D:
2374 case GL_UNSIGNED_INT_SAMPLER_3D:
2375 return TEXTURE_3D;
2376 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002377 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002378 return TEXTURE_CUBE;
2379 case GL_INT_SAMPLER_CUBE:
2380 case GL_UNSIGNED_INT_SAMPLER_CUBE:
2381 //UNIMPLEMENTED();
2382 infoLog.append("Integer cube texture sampling is currently not supported by ANGLE and returns a black color.");
2383 return TEXTURE_CUBE;
2384 case GL_SAMPLER_2D_ARRAY:
2385 case GL_INT_SAMPLER_2D_ARRAY:
2386 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002387 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002388 return TEXTURE_2D_ARRAY;
2389 default: UNREACHABLE();
2390 }
2391
2392 return TEXTURE_2D;
2393}
2394
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002395bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002396{
Jamie Madillfcef3362013-11-13 19:37:19 -05002397 if (constant.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002398 {
2399 if (constant.arraySize > 0)
2400 {
2401 unsigned int elementRegisterIndex = constant.registerIndex;
2402
2403 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2404 {
2405 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2406 {
2407 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002408 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madillfcef3362013-11-13 19:37:19 -05002409 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
2410 elementRegisterIndex, field.elementIndex);
2411
2412 fieldUniform.fields = field.fields;
2413
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002414 if (!defineUniform(shader, fieldUniform, infoLog))
2415 {
2416 return false;
2417 }
2418 elementRegisterIndex += totalRegisterCount(field);
2419 }
2420 }
2421 }
2422 else
2423 {
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002424 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2425 {
2426 const sh::Uniform &field = constant.fields[fieldIndex];
2427 const std::string &uniformName = constant.name + "." + field.name;
2428
Jamie Madill56093782013-08-30 13:21:11 -04002429 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
2430 field.registerIndex, field.elementIndex);
2431
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002432 fieldUniform.fields = field.fields;
2433
2434 if (!defineUniform(shader, fieldUniform, infoLog))
2435 {
2436 return false;
2437 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002438 }
2439 }
2440
2441 return true;
2442 }
2443
Nicolas Capense6050882013-07-08 10:43:10 -04002444 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002445 {
2446 unsigned int samplerIndex = constant.registerIndex;
2447
2448 do
2449 {
2450 if (shader == GL_VERTEX_SHADER)
2451 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002452 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002453 {
2454 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002455 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002456 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2457 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2458 }
2459 else
2460 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002461 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002462 return false;
2463 }
2464 }
2465 else if (shader == GL_FRAGMENT_SHADER)
2466 {
2467 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2468 {
2469 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002470 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002471 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2472 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2473 }
2474 else
2475 {
2476 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2477 return false;
2478 }
2479 }
2480 else UNREACHABLE();
2481
2482 samplerIndex++;
2483 }
2484 while (samplerIndex < constant.registerIndex + constant.arraySize);
2485 }
2486
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002487 Uniform *uniform = NULL;
2488 GLint location = getUniformLocation(constant.name);
2489
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002490 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002491 {
2492 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002493 }
2494 else
2495 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002496 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
Jamie Madill56093782013-08-30 13:21:11 -04002497 uniform->registerElement = constant.elementIndex;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002498 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002499
2500 if (!uniform)
2501 {
2502 return false;
2503 }
2504
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002505 if (shader == GL_FRAGMENT_SHADER)
2506 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002507 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002508 }
2509 else if (shader == GL_VERTEX_SHADER)
2510 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002511 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002512 }
2513 else UNREACHABLE();
2514
2515 if (location >= 0)
2516 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002517 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002518 }
2519
2520 mUniforms.push_back(uniform);
2521 unsigned int uniformIndex = mUniforms.size() - 1;
2522
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002523 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002524 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002525 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002526 }
2527
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002528 if (shader == GL_VERTEX_SHADER)
2529 {
2530 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2531 {
2532 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2533 return false;
2534 }
2535 }
2536 else if (shader == GL_FRAGMENT_SHADER)
2537 {
2538 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2539 {
2540 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2541 return false;
2542 }
2543 }
2544 else UNREACHABLE();
2545
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002546 return true;
2547}
2548
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002549bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2550{
2551 const char* blockName = vertexInterfaceBlock.name.c_str();
2552
2553 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002554 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002555 {
2556 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2557 return false;
2558 }
2559
2560 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2561 {
2562 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2563 return false;
2564 }
2565
Jamie Madill9060a4e2013-08-12 16:22:57 -07002566 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2567 {
2568 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2569 return false;
2570 }
2571
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002572 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002573 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2574 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002575 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2576 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002577
2578 if (vertexMember.name != fragmentMember.name)
2579 {
Jamie Madill28167c62013-08-30 13:21:10 -04002580 infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002581 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2582 return false;
2583 }
2584
Jamie Madill28167c62013-08-30 13:21:10 -04002585 std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002586 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002587 {
2588 return false;
2589 }
2590 }
2591
2592 return true;
2593}
2594
2595bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2596{
2597 // Check that interface blocks defined in the vertex and fragment shaders are identical
2598 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2599 UniformBlockMap linkedUniformBlocks;
2600
2601 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2602 {
2603 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2604 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2605 }
2606
2607 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2608 {
2609 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2610 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2611 if (entry != linkedUniformBlocks.end())
2612 {
2613 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2614 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2615 {
2616 return false;
2617 }
2618 }
2619 }
2620
2621 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2622 {
2623 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2624 {
2625 return false;
2626 }
2627 }
2628
2629 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2630 {
2631 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2632 {
2633 return false;
2634 }
2635 }
2636
2637 return true;
2638}
2639
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002640void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002641{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002642 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002643 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002644 const sh::InterfaceBlockField &field = fields[uniformIndex];
2645 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002646
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002647 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002648 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002649 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002650 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002651 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002652 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002653 const std::string uniformElementName = fieldName + arrayString(arrayElement);
2654 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002655 }
2656 }
2657 else
2658 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002659 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002660 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002661 }
2662 else
2663 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002664 Uniform *newUniform = new Uniform(field.type, field.precision, fieldName, field.arraySize,
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002665 blockIndex, **blockInfoItr);
2666
2667 // add to uniform list, but not index, since uniform block uniforms have no location
2668 blockUniformIndexes->push_back(mUniforms.size());
2669 mUniforms.push_back(newUniform);
2670 (*blockInfoItr)++;
2671 }
2672 }
2673}
2674
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002675bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2676{
2677 // create uniform block entries if they do not exist
2678 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2679 {
2680 std::vector<unsigned int> blockUniformIndexes;
2681 const unsigned int blockIndex = mUniformBlocks.size();
2682
2683 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002684 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002685 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002686
2687 // create all the uniform blocks
2688 if (interfaceBlock.arraySize > 0)
2689 {
2690 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2691 {
2692 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2693 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2694 mUniformBlocks.push_back(newUniformBlock);
2695 }
2696 }
2697 else
2698 {
2699 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2700 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2701 mUniformBlocks.push_back(newUniformBlock);
2702 }
2703 }
2704
2705 // Assign registers to the uniform blocks
2706 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2707 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2708 ASSERT(blockIndex != GL_INVALID_INDEX);
2709 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2710
2711 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2712 {
2713 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2714 ASSERT(uniformBlock->name == interfaceBlock.name);
2715
2716 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2717 {
2718 return false;
2719 }
2720 }
2721
2722 return true;
2723}
2724
2725bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2726{
2727 if (shader == GL_VERTEX_SHADER)
2728 {
2729 uniformBlock->vsRegisterIndex = registerIndex;
2730 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2731
2732 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2733 {
2734 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2735 return false;
2736 }
2737 }
2738 else if (shader == GL_FRAGMENT_SHADER)
2739 {
2740 uniformBlock->psRegisterIndex = registerIndex;
2741 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2742
2743 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2744 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002745 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002746 return false;
2747 }
2748 }
2749 else UNREACHABLE();
2750
2751 return true;
2752}
2753
Jamie Madilla6da33a2013-08-30 13:21:07 -04002754std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002755{
2756 // for now we only handle point sprite emulation
2757 ASSERT(usesPointSpriteEmulation());
2758 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2759}
2760
Jamie Madilla6da33a2013-08-30 13:21:07 -04002761std::string ProgramBinary::generatePointSpriteHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002762{
2763 ASSERT(registers >= 0);
2764 ASSERT(vertexShader->mUsesPointSize);
2765 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2766
2767 std::string geomHLSL;
2768
2769 std::string varyingSemantic = "TEXCOORD";
2770
2771 std::string fragCoordSemantic;
2772 std::string pointCoordSemantic;
2773
2774 int reservedRegisterIndex = registers;
2775
2776 if (fragmentShader->mUsesFragCoord)
2777 {
2778 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2779 }
2780
2781 if (fragmentShader->mUsesPointCoord)
2782 {
2783 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2784 }
2785
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002786 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2787 "\n"
2788 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002789 "{\n";
2790
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002791 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002792
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002793 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002794
2795 if (fragmentShader->mUsesFragCoord)
2796 {
2797 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2798 }
2799
2800 geomHLSL += " float gl_PointSize : PSIZE;\n"
2801 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002802 "};\n"
2803 "\n"
2804 "struct GS_OUTPUT\n"
2805 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002806
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002807 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002808
2809 if (fragmentShader->mUsesFragCoord)
2810 {
2811 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2812 }
2813
2814 if (fragmentShader->mUsesPointCoord)
2815 {
2816 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2817 }
2818
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002819 geomHLSL += " float gl_PointSize : PSIZE;\n"
2820 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002821 "};\n"
2822 "\n"
2823 "static float2 pointSpriteCorners[] = \n"
2824 "{\n"
2825 " float2( 0.5f, -0.5f),\n"
2826 " float2( 0.5f, 0.5f),\n"
2827 " float2(-0.5f, -0.5f),\n"
2828 " float2(-0.5f, 0.5f)\n"
2829 "};\n"
2830 "\n"
2831 "static float2 pointSpriteTexcoords[] = \n"
2832 "{\n"
2833 " float2(1.0f, 1.0f),\n"
2834 " float2(1.0f, 0.0f),\n"
2835 " float2(0.0f, 1.0f),\n"
2836 " float2(0.0f, 0.0f)\n"
2837 "};\n"
2838 "\n"
2839 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2840 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2841 "\n"
2842 "[maxvertexcount(4)]\n"
2843 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2844 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002845 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2846 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002847
2848 for (int r = 0; r < registers; r++)
2849 {
2850 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2851 }
2852
2853 if (fragmentShader->mUsesFragCoord)
2854 {
2855 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2856 }
2857
2858 geomHLSL += " \n"
2859 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2860 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002861 " 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 +00002862
2863 for (int corner = 0; corner < 4; corner++)
2864 {
2865 geomHLSL += " \n"
2866 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2867
2868 if (fragmentShader->mUsesPointCoord)
2869 {
2870 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2871 }
2872
2873 geomHLSL += " outStream.Append(output);\n";
2874 }
2875
2876 geomHLSL += " \n"
2877 " outStream.RestartStrip();\n"
2878 "}\n";
2879
2880 return geomHLSL;
2881}
2882
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002883// This method needs to match OutputHLSL::decorate
2884std::string ProgramBinary::decorateAttribute(const std::string &name)
2885{
2886 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2887 {
2888 return "_" + name;
2889 }
2890
2891 return name;
2892}
2893
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002894bool ProgramBinary::isValidated() const
2895{
2896 return mValidated;
2897}
2898
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002899void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002900{
2901 // Skip over inactive attributes
2902 unsigned int activeAttribute = 0;
2903 unsigned int attribute;
2904 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2905 {
2906 if (mLinkedAttribute[attribute].name.empty())
2907 {
2908 continue;
2909 }
2910
2911 if (activeAttribute == index)
2912 {
2913 break;
2914 }
2915
2916 activeAttribute++;
2917 }
2918
2919 if (bufsize > 0)
2920 {
2921 const char *string = mLinkedAttribute[attribute].name.c_str();
2922
2923 strncpy(name, string, bufsize);
2924 name[bufsize - 1] = '\0';
2925
2926 if (length)
2927 {
2928 *length = strlen(name);
2929 }
2930 }
2931
2932 *size = 1; // Always a single 'type' instance
2933
2934 *type = mLinkedAttribute[attribute].type;
2935}
2936
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002937GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002938{
2939 int count = 0;
2940
2941 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2942 {
2943 if (!mLinkedAttribute[attributeIndex].name.empty())
2944 {
2945 count++;
2946 }
2947 }
2948
2949 return count;
2950}
2951
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002952GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002953{
2954 int maxLength = 0;
2955
2956 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2957 {
2958 if (!mLinkedAttribute[attributeIndex].name.empty())
2959 {
2960 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2961 }
2962 }
2963
2964 return maxLength;
2965}
2966
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002967void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002968{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002969 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002970
2971 if (bufsize > 0)
2972 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002973 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002974
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002975 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002976 {
2977 string += "[0]";
2978 }
2979
2980 strncpy(name, string.c_str(), bufsize);
2981 name[bufsize - 1] = '\0';
2982
2983 if (length)
2984 {
2985 *length = strlen(name);
2986 }
2987 }
2988
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002989 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002990
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002991 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002992}
2993
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002994GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002995{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002996 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002997}
2998
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002999GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003000{
3001 int maxLength = 0;
3002
3003 unsigned int numUniforms = mUniforms.size();
3004 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
3005 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00003006 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003007 {
3008 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
3009 if (mUniforms[uniformIndex]->isArray())
3010 {
3011 length += 3; // Counting in "[0]".
3012 }
3013 maxLength = std::max(length, maxLength);
3014 }
3015 }
3016
3017 return maxLength;
3018}
3019
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003020GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
3021{
3022 const gl::Uniform& uniform = *mUniforms[index];
3023
3024 switch (pname)
3025 {
3026 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
3027 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00003028 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00003029 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003030
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00003031 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
3032 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
3033 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
3034 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003035
3036 default:
3037 UNREACHABLE();
3038 break;
3039 }
3040 return 0;
3041}
3042
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00003043void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
3044{
3045 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
3046
3047 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3048
3049 if (bufSize > 0)
3050 {
3051 std::string string = uniformBlock.name;
3052
3053 if (uniformBlock.isArrayElement())
3054 {
Jamie Madill63491ea2013-06-06 11:56:45 -04003055 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00003056 }
3057
3058 strncpy(uniformBlockName, string.c_str(), bufSize);
3059 uniformBlockName[bufSize - 1] = '\0';
3060
3061 if (length)
3062 {
3063 *length = strlen(uniformBlockName);
3064 }
3065 }
3066}
3067
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003068void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
3069{
3070 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
3071
3072 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3073
3074 switch (pname)
3075 {
3076 case GL_UNIFORM_BLOCK_DATA_SIZE:
3077 *params = static_cast<GLint>(uniformBlock.dataSize);
3078 break;
3079 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00003080 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003081 break;
3082 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
3083 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
3084 break;
3085 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
3086 {
3087 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
3088 {
3089 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
3090 }
3091 }
3092 break;
3093 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
3094 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
3095 break;
3096 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
3097 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
3098 break;
3099 default: UNREACHABLE();
3100 }
3101}
3102
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00003103GLuint ProgramBinary::getActiveUniformBlockCount() const
3104{
3105 return mUniformBlocks.size();
3106}
3107
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00003108GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
3109{
3110 unsigned int maxLength = 0;
3111
3112 unsigned int numUniformBlocks = mUniformBlocks.size();
3113 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
3114 {
3115 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3116 if (!uniformBlock.name.empty())
3117 {
3118 const unsigned int length = uniformBlock.name.length() + 1;
3119
3120 // Counting in "[0]".
3121 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
3122
3123 maxLength = std::max(length + arrayLength, maxLength);
3124 }
3125 }
3126
3127 return maxLength;
3128}
3129
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003130void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003131{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003132 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003133 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003134 {
3135 mValidated = false;
3136 }
3137 else
3138 {
3139 mValidated = true;
3140 }
3141}
3142
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003143bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003144{
3145 // if any two active samplers in a program are of different types, but refer to the same
3146 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3147 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3148
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00003149 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003150 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003151
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003152 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003153 {
3154 textureUnitType[i] = TEXTURE_UNKNOWN;
3155 }
3156
3157 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3158 {
3159 if (mSamplersPS[i].active)
3160 {
3161 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3162
3163 if (unit >= maxCombinedTextureImageUnits)
3164 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003165 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003166 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003167 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003168 }
3169
3170 return false;
3171 }
3172
3173 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3174 {
3175 if (mSamplersPS[i].textureType != textureUnitType[unit])
3176 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003177 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003178 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003179 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003180 }
3181
3182 return false;
3183 }
3184 }
3185 else
3186 {
3187 textureUnitType[unit] = mSamplersPS[i].textureType;
3188 }
3189 }
3190 }
3191
3192 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3193 {
3194 if (mSamplersVS[i].active)
3195 {
3196 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3197
3198 if (unit >= maxCombinedTextureImageUnits)
3199 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003200 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003201 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003202 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003203 }
3204
3205 return false;
3206 }
3207
3208 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3209 {
3210 if (mSamplersVS[i].textureType != textureUnitType[unit])
3211 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003212 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003213 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003214 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003215 }
3216
3217 return false;
3218 }
3219 }
3220 else
3221 {
3222 textureUnitType[unit] = mSamplersVS[i].textureType;
3223 }
3224 }
3225 }
3226
3227 return true;
3228}
3229
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003230ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3231{
3232}
3233
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003234struct AttributeSorter
3235{
3236 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3237 : originalIndices(semanticIndices)
3238 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003239 }
3240
3241 bool operator()(int a, int b)
3242 {
3243 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3244 }
3245
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003246 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3247};
3248
Al Patrick3f2daa82013-08-07 12:58:57 -07003249void ProgramBinary::initAttributesByLayout()
3250{
3251 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3252 {
3253 mAttributesByLayout[i] = i;
3254 }
3255
3256 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
3257}
3258
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003259void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3260{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003261 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3262
3263 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3264 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003265 oldTranslatedAttributes[i] = attributes[i];
3266 }
3267
3268 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3269 {
Al Patrick3f2daa82013-08-07 12:58:57 -07003270 int oldIndex = mAttributesByLayout[i];
3271 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003272 attributes[i] = oldTranslatedAttributes[oldIndex];
3273 }
3274}
3275
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003276}