blob: 4ee12693ff4aba9fbeca309f8b93bf287dbc613f [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
102}
103
Jamie Madill63491ea2013-06-06 11:56:45 -0400104VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000105 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106{
107}
108
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000109unsigned int ProgramBinary::mCurrentSerial = 1;
110
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000111ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000112{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000113 mPixelExecutable = NULL;
114 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000115 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000117 mValidated = false;
118
119 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
120 {
121 mSemanticIndex[index] = -1;
122 }
123
124 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
125 {
126 mSamplersPS[index].active = false;
127 }
128
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000129 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000130 {
131 mSamplersVS[index].active = false;
132 }
133
134 mUsedVertexSamplerRange = 0;
135 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000136 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000137 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000138}
139
140ProgramBinary::~ProgramBinary()
141{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000142 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000143 mPixelExecutable = NULL;
144
daniel@transgaming.com95892412012-11-28 20:59:09 +0000145 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000146 mVertexExecutable = NULL;
147
148 delete mGeometryExecutable;
149 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000150
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000151 while (!mUniforms.empty())
152 {
153 delete mUniforms.back();
154 mUniforms.pop_back();
155 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000156
157 while (!mUniformBlocks.empty())
158 {
159 delete mUniformBlocks.back();
160 mUniformBlocks.pop_back();
161 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000162}
163
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000164unsigned int ProgramBinary::getSerial() const
165{
166 return mSerial;
167}
168
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000169int ProgramBinary::getShaderVersion() const
170{
171 return mShaderVersion;
172}
173
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000174unsigned int ProgramBinary::issueSerial()
175{
176 return mCurrentSerial++;
177}
178
daniel@transgaming.com95892412012-11-28 20:59:09 +0000179rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000180{
181 return mPixelExecutable;
182}
183
daniel@transgaming.com95892412012-11-28 20:59:09 +0000184rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000185{
186 return mVertexExecutable;
187}
188
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000189rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
190{
191 return mGeometryExecutable;
192}
193
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000194GLuint ProgramBinary::getAttributeLocation(const char *name)
195{
196 if (name)
197 {
198 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
199 {
200 if (mLinkedAttribute[index].name == std::string(name))
201 {
202 return index;
203 }
204 }
205 }
206
207 return -1;
208}
209
210int ProgramBinary::getSemanticIndex(int attributeIndex)
211{
212 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
213
214 return mSemanticIndex[attributeIndex];
215}
216
217// Returns one more than the highest sampler index used.
218GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
219{
220 switch (type)
221 {
222 case SAMPLER_PIXEL:
223 return mUsedPixelSamplerRange;
224 case SAMPLER_VERTEX:
225 return mUsedVertexSamplerRange;
226 default:
227 UNREACHABLE();
228 return 0;
229 }
230}
231
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000232bool ProgramBinary::usesPointSize() const
233{
234 return mUsesPointSize;
235}
236
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000237bool ProgramBinary::usesPointSpriteEmulation() const
238{
239 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
240}
241
242bool ProgramBinary::usesGeometryShader() const
243{
244 return usesPointSpriteEmulation();
245}
246
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000247// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
248// index (0-15 for the pixel shader and 0-3 for the vertex shader).
249GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
250{
251 GLint logicalTextureUnit = -1;
252
253 switch (type)
254 {
255 case SAMPLER_PIXEL:
256 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
257
258 if (mSamplersPS[samplerIndex].active)
259 {
260 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
261 }
262 break;
263 case SAMPLER_VERTEX:
264 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
265
266 if (mSamplersVS[samplerIndex].active)
267 {
268 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
269 }
270 break;
271 default: UNREACHABLE();
272 }
273
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000274 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000275 {
276 return logicalTextureUnit;
277 }
278
279 return -1;
280}
281
282// Returns the texture type for a given Direct3D 9 sampler type and
283// index (0-15 for the pixel shader and 0-3 for the vertex shader).
284TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
285{
286 switch (type)
287 {
288 case SAMPLER_PIXEL:
289 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
290 ASSERT(mSamplersPS[samplerIndex].active);
291 return mSamplersPS[samplerIndex].textureType;
292 case SAMPLER_VERTEX:
293 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
294 ASSERT(mSamplersVS[samplerIndex].active);
295 return mSamplersVS[samplerIndex].textureType;
296 default: UNREACHABLE();
297 }
298
299 return TEXTURE_2D;
300}
301
302GLint ProgramBinary::getUniformLocation(std::string name)
303{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000304 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000305
306 unsigned int numUniforms = mUniformIndex.size();
307 for (unsigned int location = 0; location < numUniforms; location++)
308 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000309 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000310 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000311 const int index = mUniformIndex[location].index;
312 const bool isArray = mUniforms[index]->isArray();
313
314 if ((isArray && mUniformIndex[location].element == subscript) ||
315 (subscript == GL_INVALID_INDEX))
316 {
317 return location;
318 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000319 }
320 }
321
322 return -1;
323}
324
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000325GLuint ProgramBinary::getUniformIndex(std::string name)
326{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000327 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000328
329 // The app is not allowed to specify array indices other than 0 for arrays of basic types
330 if (subscript != 0 && subscript != GL_INVALID_INDEX)
331 {
332 return GL_INVALID_INDEX;
333 }
334
335 unsigned int numUniforms = mUniforms.size();
336 for (unsigned int index = 0; index < numUniforms; index++)
337 {
338 if (mUniforms[index]->name == name)
339 {
340 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
341 {
342 return index;
343 }
344 }
345 }
346
347 return GL_INVALID_INDEX;
348}
349
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000350GLuint ProgramBinary::getUniformBlockIndex(std::string name)
351{
352 unsigned int subscript = parseAndStripArrayIndex(&name);
353
354 unsigned int numUniformBlocks = mUniformBlocks.size();
355 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
356 {
357 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
358 if (uniformBlock.name == name)
359 {
360 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
361 if (subscript == uniformBlock.elementIndex || arrayElementZero)
362 {
363 return blockIndex;
364 }
365 }
366 }
367
368 return GL_INVALID_INDEX;
369}
370
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000371UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
372{
373 ASSERT(blockIndex < mUniformBlocks.size());
374 return mUniformBlocks[blockIndex];
375}
376
Jamie Madilld1e78c92013-06-20 11:55:50 -0400377GLint ProgramBinary::getFragDataLocation(const char *name) const
378{
379 std::string baseName(name);
380 unsigned int arrayIndex;
381 arrayIndex = parseAndStripArrayIndex(&baseName);
382
383 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
384 {
385 const VariableLocation &outputVariable = locationIt->second;
386
387 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
388 {
389 return static_cast<GLint>(locationIt->first);
390 }
391 }
392
393 return -1;
394}
395
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000396template <typename T>
397bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398{
399 if (location < 0 || location >= (int)mUniformIndex.size())
400 {
401 return false;
402 }
403
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000404 const int components = UniformComponentCount(targetUniformType);
405 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
406
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000407 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
408 targetUniform->dirty = true;
409
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000410 int elementCount = targetUniform->elementCount();
411
412 if (elementCount == 1 && count > 1)
413 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
414
415 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
416
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000417 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000418 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000419 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000420
421 for (int i = 0; i < count; i++)
422 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000423 for (int c = 0; c < components; c++)
424 {
425 target[c] = v[c];
426 }
427 for (int c = components; c < 4; c++)
428 {
429 target[c] = 0;
430 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000431 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000432 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000433 }
434 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000435 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000436 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000437 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000439 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000440 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000441 for (int c = 0; c < components; c++)
442 {
443 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
444 }
445 for (int c = components; c < 4; c++)
446 {
447 boolParams[c] = GL_FALSE;
448 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000449 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000450 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000451 }
452 }
453 else
454 {
455 return false;
456 }
457
458 return true;
459}
460
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000461bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
462{
463 return setUniform(location, count, v, GL_FLOAT);
464}
465
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000466bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
467{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000468 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000469}
470
471bool ProgramBinary::setUniform3fv(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_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000474}
475
476bool ProgramBinary::setUniform4fv(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_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000479}
480
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000481template<typename T>
482void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000483{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000484 int copyWidth = std::min(targetHeight, srcWidth);
485 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000486
487 for (int x = 0; x < copyWidth; x++)
488 {
489 for (int y = 0; y < copyHeight; y++)
490 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000491 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000492 }
493 }
494 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000495 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000496 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000497 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000498 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000499 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000500 }
501 }
502 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000503 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000504 {
505 for (int x = 0; x < targetWidth; x++)
506 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000507 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000508 }
509 }
510}
511
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000512template<typename T>
513void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
514{
515 int copyWidth = std::min(targetWidth, srcWidth);
516 int copyHeight = std::min(targetHeight, srcHeight);
517
518 for (int y = 0; y < copyHeight; y++)
519 {
520 for (int x = 0; x < copyWidth; x++)
521 {
522 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
523 }
524 }
525 // clear unfilled right side
526 for (int y = 0; y < copyHeight; y++)
527 {
528 for (int x = copyWidth; x < targetWidth; x++)
529 {
530 target[y * targetWidth + x] = static_cast<T>(0);
531 }
532 }
533 // clear unfilled bottom.
534 for (int y = copyHeight; y < targetHeight; y++)
535 {
536 for (int x = 0; x < targetWidth; x++)
537 {
538 target[y * targetWidth + x] = static_cast<T>(0);
539 }
540 }
541}
542
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000543template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000544bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000545{
546 if (location < 0 || location >= (int)mUniformIndex.size())
547 {
548 return false;
549 }
550
551 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
552 targetUniform->dirty = true;
553
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000554 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555 {
556 return false;
557 }
558
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000559 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000561 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
563
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000564 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000565 const unsigned int targetMatrixStride = (4 * rows);
566 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000567
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568 for (int i = 0; i < count; i++)
569 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000570 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
571 if (transpose == GL_FALSE)
572 {
573 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
574 }
575 else
576 {
577 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
578 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000579 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000580 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000581 }
582
583 return true;
584}
585
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000586bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000587{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000588 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000589}
590
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000591bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000592{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000593 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000594}
595
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000596bool ProgramBinary::setUniformMatrix4fv(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<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000599}
600
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000601bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000602{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000603 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000604}
605
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000606bool ProgramBinary::setUniformMatrix3x2fv(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<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
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::setUniformMatrix2x4fv(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<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
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::setUniformMatrix4x2fv(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<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
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::setUniformMatrix3x4fv(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<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
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::setUniformMatrix4x3fv(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<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000629}
630
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
632{
633 if (location < 0 || location >= (int)mUniformIndex.size())
634 {
635 return false;
636 }
637
638 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
639 targetUniform->dirty = true;
640
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000641 int elementCount = targetUniform->elementCount();
642
643 if (elementCount == 1 && count > 1)
644 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
645
646 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
647
Nicolas Capense6050882013-07-08 10:43:10 -0400648 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000649 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000650 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000651
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000652 for (int i = 0; i < count; i++)
653 {
654 target[0] = v[0];
655 target[1] = 0;
656 target[2] = 0;
657 target[3] = 0;
658 target += 4;
659 v += 1;
660 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000661 }
662 else if (targetUniform->type == GL_BOOL)
663 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000664 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000666 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000668 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
669 boolParams[1] = GL_FALSE;
670 boolParams[2] = GL_FALSE;
671 boolParams[3] = GL_FALSE;
672 boolParams += 4;
673 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000674 }
675 }
676 else
677 {
678 return false;
679 }
680
681 return true;
682}
683
684bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
685{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000686 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000687}
688
689bool ProgramBinary::setUniform3iv(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_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692}
693
694bool ProgramBinary::setUniform4iv(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_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697}
698
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000699bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
700{
701 return setUniform(location, count, v, GL_UNSIGNED_INT);
702}
703
704bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
705{
706 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
707}
708
709bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
710{
711 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
712}
713
714bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
715{
716 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
717}
718
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000719template <typename T>
720bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000721{
722 if (location < 0 || location >= (int)mUniformIndex.size())
723 {
724 return false;
725 }
726
727 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
728
729 // sized queries -- ensure the provided buffer is large enough
730 if (bufSize)
731 {
732 int requiredBytes = UniformExternalSize(targetUniform->type);
733 if (*bufSize < requiredBytes)
734 {
735 return false;
736 }
737 }
738
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000740 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000741 const int rows = VariableRowCount(targetUniform->type);
742 const int cols = VariableColumnCount(targetUniform->type);
743 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
744 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000745 else if (uniformType == UniformComponentType(targetUniform->type))
746 {
747 unsigned int size = UniformComponentCount(targetUniform->type);
748 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
749 size * sizeof(T));
750 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000751 else
752 {
753 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000754 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000756 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000757 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000758 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000759
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000760 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000762 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000763 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000764 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000765 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000766
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000767 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000768 {
769 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
770
771 for (unsigned int i = 0; i < size; i++)
772 {
773 params[i] = static_cast<T>(floatParams[i]);
774 }
775 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000776 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000777
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000778 case GL_INT:
779 {
780 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
781
782 for (unsigned int i = 0; i < size; i++)
783 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000784 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000785 }
786 }
787 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000788
789 case GL_UNSIGNED_INT:
790 {
791 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000792
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000793 for (unsigned int i = 0; i < size; i++)
794 {
795 params[i] = static_cast<T>(uintParams[i]);
796 }
797 }
798 break;
799
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000800 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000801 }
802 }
803
804 return true;
805}
806
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000807bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
808{
809 return getUniformv(location, bufSize, params, GL_FLOAT);
810}
811
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000812bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
813{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000814 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000815}
816
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000817bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
818{
819 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
820}
821
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000822void ProgramBinary::dirtyAllUniforms()
823{
824 unsigned int numUniforms = mUniforms.size();
825 for (unsigned int index = 0; index < numUniforms; index++)
826 {
827 mUniforms[index]->dirty = true;
828 }
829}
830
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000831// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000832void ProgramBinary::applyUniforms()
833{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000834 // Retrieve sampler uniform values
835 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
836 {
837 Uniform *targetUniform = *ub;
838
839 if (targetUniform->dirty)
840 {
Nicolas Capense6050882013-07-08 10:43:10 -0400841 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000842 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000843 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000844 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000845
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000846 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000847 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000848 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000849
850 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000851 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000852 unsigned int samplerIndex = firstIndex + i;
853
854 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000855 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000856 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000857 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000858 }
859 }
860 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000861
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000862 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000863 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000864 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000865
866 for (int i = 0; i < count; i++)
867 {
868 unsigned int samplerIndex = firstIndex + i;
869
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000870 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000871 {
872 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000873 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000874 }
875 }
876 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000877 }
878 }
879 }
880
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000881 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000882}
883
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000884bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
885{
886 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
887 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
888
889 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
890 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
891
892 ASSERT(boundBuffers.size() == mUniformBlocks.size());
893
894 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
895 {
896 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
897 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
898
899 ASSERT(uniformBlock && uniformBuffer);
900
901 if (uniformBuffer->size() < uniformBlock->dataSize)
902 {
903 // undefined behaviour
904 return false;
905 }
906
907 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
908
909 if (uniformBlock->isReferencedByVertexShader())
910 {
911 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
912 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
913 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
914 vertexUniformBuffers[registerIndex] = uniformBuffer;
915 }
916
917 if (uniformBlock->isReferencedByFragmentShader())
918 {
919 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
920 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
921 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
922 fragmentUniformBuffers[registerIndex] = uniformBuffer;
923 }
924 }
925
926 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
927}
928
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000929// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
930// Returns the number of used varying registers, or -1 if unsuccesful
Jamie Madilla6da33a2013-08-30 13:21:07 -0400931int ProgramBinary::packVaryings(InfoLog &infoLog, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000932{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000933 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000934
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000935 fragmentShader->resetVaryingsRegisterAssignment();
936
Jamie Madillce79dda2013-08-30 13:21:06 -0400937 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000938 {
Jamie Madilla6da33a2013-08-30 13:21:07 -0400939 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000940 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -0400941
942 // matrices within varying structs are not transposed
943 int registers = (varying->isStruct() ? sh::HLSLVariableRegisterCount(*varying) : gl::VariableRowCount(transposedType)) * varying->elementCount();
944 int elements = (varying->isStruct() ? 4 : VariableColumnCount(transposedType));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000945 bool success = false;
946
Jamie Madill28167c62013-08-30 13:21:10 -0400947 if (elements == 2 || elements == 3 || elements == 4)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000948 {
Jamie Madill28167c62013-08-30 13:21:10 -0400949 for (int r = 0; r <= maxVaryingVectors - registers && !success; r++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000950 {
951 bool available = true;
952
Jamie Madill28167c62013-08-30 13:21:10 -0400953 for (int y = 0; y < registers && available; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000954 {
Jamie Madill28167c62013-08-30 13:21:10 -0400955 for (int x = 0; x < elements && available; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000956 {
957 if (packing[r + y][x])
958 {
959 available = false;
960 }
961 }
962 }
963
964 if (available)
965 {
Jamie Madill139b9092013-08-30 13:21:06 -0400966 varying->registerIndex = r;
967 varying->elementIndex = 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000968
Jamie Madill28167c62013-08-30 13:21:10 -0400969 for (int y = 0; y < registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000970 {
Jamie Madill28167c62013-08-30 13:21:10 -0400971 for (int x = 0; x < elements; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000972 {
973 packing[r + y][x] = &*varying;
974 }
975 }
976
977 success = true;
978 }
979 }
980
Jamie Madill28167c62013-08-30 13:21:10 -0400981 if (!success && elements == 2)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000982 {
Jamie Madill28167c62013-08-30 13:21:10 -0400983 for (int r = maxVaryingVectors - registers; r >= 0 && !success; r--)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000984 {
985 bool available = true;
986
Jamie Madill28167c62013-08-30 13:21:10 -0400987 for (int y = 0; y < registers && available; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000988 {
989 for (int x = 2; x < 4 && available; x++)
990 {
991 if (packing[r + y][x])
992 {
993 available = false;
994 }
995 }
996 }
997
998 if (available)
999 {
Jamie Madill139b9092013-08-30 13:21:06 -04001000 varying->registerIndex = r;
1001 varying->elementIndex = 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001002
Jamie Madill28167c62013-08-30 13:21:10 -04001003 for (int y = 0; y < registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001004 {
1005 for (int x = 2; x < 4; x++)
1006 {
1007 packing[r + y][x] = &*varying;
1008 }
1009 }
1010
1011 success = true;
1012 }
1013 }
1014 }
1015 }
Jamie Madill28167c62013-08-30 13:21:10 -04001016 else if (elements == 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001017 {
1018 int space[4] = {0};
1019
1020 for (int y = 0; y < maxVaryingVectors; y++)
1021 {
1022 for (int x = 0; x < 4; x++)
1023 {
1024 space[x] += packing[y][x] ? 0 : 1;
1025 }
1026 }
1027
1028 int column = 0;
1029
1030 for (int x = 0; x < 4; x++)
1031 {
Jamie Madill28167c62013-08-30 13:21:10 -04001032 if (space[x] >= registers && space[x] < space[column])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001033 {
1034 column = x;
1035 }
1036 }
1037
Jamie Madill28167c62013-08-30 13:21:10 -04001038 if (space[column] >= registers)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001039 {
1040 for (int r = 0; r < maxVaryingVectors; r++)
1041 {
1042 if (!packing[r][column])
1043 {
Jamie Madill139b9092013-08-30 13:21:06 -04001044 varying->registerIndex = r;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001045
Jamie Madill28167c62013-08-30 13:21:10 -04001046 for (int y = r; y < r + registers; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001047 {
1048 packing[y][column] = &*varying;
1049 }
1050
1051 break;
1052 }
1053 }
1054
Jamie Madill139b9092013-08-30 13:21:06 -04001055 varying->elementIndex = column;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001056
1057 success = true;
1058 }
1059 }
1060 else UNREACHABLE();
1061
1062 if (!success)
1063 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001064 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001065
1066 return -1;
1067 }
1068 }
1069
1070 // Return the number of used registers
1071 int registers = 0;
1072
1073 for (int r = 0; r < maxVaryingVectors; r++)
1074 {
1075 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1076 {
1077 registers++;
1078 }
1079 }
1080
1081 return registers;
1082}
1083
Jamie Madill46131a32013-06-20 11:55:50 -04001084void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1085{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001086 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001087
1088 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1089 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001090 const sh::Attribute &outputVariable = outputVars[outputVariableIndex];
Jamie Madill46131a32013-06-20 11:55:50 -04001091 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1092
1093 if (outputVariable.arraySize > 0)
1094 {
1095 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1096 {
1097 const int location = baseLocation + elementIndex;
1098 ASSERT(mOutputVariables.count(location) == 0);
1099 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1100 }
1101 }
1102 else
1103 {
1104 ASSERT(mOutputVariables.count(baseLocation) == 0);
1105 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1106 }
1107 }
1108}
1109
Jamie Madilla6da33a2013-08-30 13:21:07 -04001110bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const sh::ShaderVariable *packing[][4],
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001111 std::string& pixelHLSL, std::string& vertexHLSL,
1112 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001113{
1114 if (pixelHLSL.empty() || vertexHLSL.empty())
1115 {
1116 return false;
1117 }
1118
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001119 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1120 bool usesFragColor = fragmentShader->mUsesFragColor;
1121 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001122 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001123 {
1124 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1125 return false;
1126 }
1127
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001128 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001129 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001130 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001131
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001132 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1133
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001134 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1135 // - with a 3.0 context, the output color is copied to channel 0
1136 // - with a 2.0 context, the output color is broadcast to all channels
1137 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1138 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1139
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001140 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001141 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001142 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001143
1144 return false;
1145 }
1146
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001147 vertexShader->resetVaryingsRegisterAssignment();
1148
Jamie Madillce79dda2013-08-30 13:21:06 -04001149 for (unsigned int fragVaryingIndex = 0; fragVaryingIndex < fragmentShader->mVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001150 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001151 sh::Varying *input = &fragmentShader->mVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001152 bool matched = false;
1153
Jamie Madillce79dda2013-08-30 13:21:06 -04001154 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001156 sh::Varying *output = &vertexShader->mVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001157 if (output->name == input->name)
1158 {
Jamie Madill28167c62013-08-30 13:21:10 -04001159 if (!linkValidateVariables(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001160 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001161 return false;
1162 }
1163
Jamie Madill139b9092013-08-30 13:21:06 -04001164 output->registerIndex = input->registerIndex;
1165 output->elementIndex = input->elementIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001166
1167 matched = true;
1168 break;
1169 }
1170 }
1171
1172 if (!matched)
1173 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001174 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175
1176 return false;
1177 }
1178 }
1179
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001180 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001181 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001182 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001183 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001184 std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001185
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001186 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1187
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001188 // special varyings that use reserved registers
1189 int reservedRegisterIndex = registers;
1190 std::string fragCoordSemantic;
1191 std::string pointCoordSemantic;
1192
1193 if (fragmentShader->mUsesFragCoord)
1194 {
1195 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1196 }
1197
1198 if (fragmentShader->mUsesPointCoord)
1199 {
1200 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1201 // In DX11 we compute this in the GS.
1202 if (shaderModel == 3)
1203 {
1204 pointCoordSemantic = "TEXCOORD0";
1205 }
1206 else if (shaderModel >= 4)
1207 {
1208 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1209 }
1210 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001211
1212 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001213 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001214
1215 int semanticIndex = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001216 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
Jamie Madilldefb6742013-06-20 11:55:51 -04001217 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001218 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001219 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilldefb6742013-06-20 11:55:51 -04001220 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1221 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001222
Jamie Madilldefb6742013-06-20 11:55:51 -04001223 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001224 }
1225
1226 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001227 "\n"
1228 "struct VS_OUTPUT\n"
1229 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001230
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001231 if (shaderModel < 4)
1232 {
1233 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1234 }
1235
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001236 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001237
1238 if (fragmentShader->mUsesFragCoord)
1239 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001240 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001241 }
1242
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001243 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001244 {
1245 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1246 }
1247
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001248 if (shaderModel >= 4)
1249 {
1250 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1251 }
1252
1253 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001254 "\n"
1255 "VS_OUTPUT main(VS_INPUT input)\n"
1256 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001257
Jamie Madilldefb6742013-06-20 11:55:51 -04001258 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001259 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001260 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1261 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262
Jamie Madilldefb6742013-06-20 11:55:51 -04001263 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001264 {
1265 vertexHLSL += "transpose";
1266 }
1267
Jamie Madilldefb6742013-06-20 11:55:51 -04001268 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001269 }
1270
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001271 if (shaderModel >= 4)
1272 {
1273 vertexHLSL += "\n"
1274 " gl_main();\n"
1275 "\n"
1276 " VS_OUTPUT output;\n"
1277 " output.gl_Position.x = gl_Position.x;\n"
1278 " output.gl_Position.y = -gl_Position.y;\n"
1279 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1280 " output.gl_Position.w = gl_Position.w;\n";
1281 }
1282 else
1283 {
1284 vertexHLSL += "\n"
1285 " gl_main();\n"
1286 "\n"
1287 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001288 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1289 " 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 +00001290 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1291 " output.gl_Position.w = gl_Position.w;\n";
1292 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001293
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001294 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001296 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001297 }
1298
1299 if (fragmentShader->mUsesFragCoord)
1300 {
1301 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1302 }
1303
Jamie Madillce79dda2013-08-30 13:21:06 -04001304 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001305 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001306 sh::Varying *varying = &vertexShader->mVaryings[vertVaryingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001307 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001308 {
Jamie Madill139b9092013-08-30 13:21:06 -04001309 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310 {
Jamie Madill28167c62013-08-30 13:21:10 -04001311 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying->type)));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001312
Jamie Madill139b9092013-08-30 13:21:06 -04001313 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314 {
Jamie Madill139b9092013-08-30 13:21:06 -04001315 int r = varying->registerIndex + elementIndex * variableRows + row;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001316 vertexHLSL += " output.v" + str(r);
1317
1318 bool sharedRegister = false; // Register used by multiple varyings
1319
1320 for (int x = 0; x < 4; x++)
1321 {
1322 if (packing[r][x] && packing[r][x] != packing[r][0])
1323 {
1324 sharedRegister = true;
1325 break;
1326 }
1327 }
1328
1329 if(sharedRegister)
1330 {
1331 vertexHLSL += ".";
1332
1333 for (int x = 0; x < 4; x++)
1334 {
1335 if (packing[r][x] == &*varying)
1336 {
1337 switch(x)
1338 {
1339 case 0: vertexHLSL += "x"; break;
1340 case 1: vertexHLSL += "y"; break;
1341 case 2: vertexHLSL += "z"; break;
1342 case 3: vertexHLSL += "w"; break;
1343 }
1344 }
1345 }
1346 }
1347
Jamie Madill139b9092013-08-30 13:21:06 -04001348 vertexHLSL += " = _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349
Jamie Madill139b9092013-08-30 13:21:06 -04001350 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001351 {
Jamie Madill139b9092013-08-30 13:21:06 -04001352 vertexHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001353 }
1354
Jamie Madill139b9092013-08-30 13:21:06 -04001355 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001356 {
Jamie Madill139b9092013-08-30 13:21:06 -04001357 vertexHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358 }
1359
1360 vertexHLSL += ";\n";
1361 }
1362 }
1363 }
1364 }
1365
1366 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001367 " return output;\n"
1368 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001369
1370 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001371 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001372
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001373 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001374
1375 if (fragmentShader->mUsesFragCoord)
1376 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001377 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001378 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001379
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001380 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1381 {
1382 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1383 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001384
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001385 // Must consume the PSIZE element if the geometry shader is not active
1386 // We won't know if we use a GS until we draw
1387 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1388 {
1389 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1390 }
1391
1392 if (fragmentShader->mUsesFragCoord)
1393 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001394 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001395 {
1396 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1397 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001398 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001399 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001400 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1401 }
1402 }
1403
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001404 pixelHLSL += "};\n"
1405 "\n"
1406 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001407 "{\n";
1408
Jamie Madill46131a32013-06-20 11:55:50 -04001409 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001410 {
Jamie Madill46131a32013-06-20 11:55:50 -04001411 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1412 {
1413 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1414 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001415
1416 if (fragmentShader->mUsesFragDepth)
1417 {
1418 pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
1419 }
Jamie Madill46131a32013-06-20 11:55:50 -04001420 }
1421 else
1422 {
1423 defineOutputVariables(fragmentShader);
1424
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001425 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001426 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1427 {
1428 const VariableLocation &outputLocation = locationIt->second;
1429 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1430 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1431
1432 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1433 " out_" + outputLocation.name + elementString +
1434 " : " + targetSemantic + str(locationIt->first) + ";\n";
1435 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001436 }
1437
1438 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001439 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001440
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001441 if (fragmentShader->mUsesFrontFacing)
1442 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001443 if (shaderModel >= 4)
1444 {
1445 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1446 "{\n";
1447 }
1448 else
1449 {
1450 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1451 "{\n";
1452 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001453 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001454 else
1455 {
1456 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1457 "{\n";
1458 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001459
1460 if (fragmentShader->mUsesFragCoord)
1461 {
1462 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1463
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001464 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001465 {
1466 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1467 " gl_FragCoord.y = input.dx_VPos.y;\n";
1468 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001469 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001470 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001471 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001472 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001473 }
1474 else
1475 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001476 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1477 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1478 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001479 }
1480
daniel@transgaming.com12985182012-12-20 20:56:31 +00001481 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001482 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001483 }
1484
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001485 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001486 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001487 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1488 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001489 }
1490
1491 if (fragmentShader->mUsesFrontFacing)
1492 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001493 if (shaderModel <= 3)
1494 {
1495 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1496 }
1497 else
1498 {
1499 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1500 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001501 }
1502
Jamie Madillce79dda2013-08-30 13:21:06 -04001503 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001504 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001505 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001506 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001507 {
Jamie Madill139b9092013-08-30 13:21:06 -04001508 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001509 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001510 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -04001511 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
Jamie Madill139b9092013-08-30 13:21:06 -04001512 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001513 {
Jamie Madill139b9092013-08-30 13:21:06 -04001514 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
1515 pixelHLSL += " _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001516
Jamie Madill139b9092013-08-30 13:21:06 -04001517 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001518 {
Jamie Madill139b9092013-08-30 13:21:06 -04001519 pixelHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001520 }
1521
Jamie Madill139b9092013-08-30 13:21:06 -04001522 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001523 {
Jamie Madill139b9092013-08-30 13:21:06 -04001524 pixelHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001525 }
1526
Jamie Madill28167c62013-08-30 13:21:10 -04001527 if (varying->isStruct())
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001528 {
Jamie Madill28167c62013-08-30 13:21:10 -04001529 pixelHLSL += " = input.v" + n + ";\n"; break;
1530 }
1531 else
1532 {
1533 switch (VariableColumnCount(transposedType))
1534 {
1535 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1536 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1537 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1538 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1539 default: UNREACHABLE();
1540 }
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001541 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001542 }
1543 }
1544 }
1545 else UNREACHABLE();
1546 }
1547
1548 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001549 " gl_main();\n"
1550 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001551 " PS_OUTPUT output;\n";
1552
Jamie Madill46131a32013-06-20 11:55:50 -04001553 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001554 {
Jamie Madill46131a32013-06-20 11:55:50 -04001555 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1556 {
1557 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001558
Jamie Madill46131a32013-06-20 11:55:50 -04001559 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1560 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001561
1562 if (fragmentShader->mUsesFragDepth)
1563 {
1564 pixelHLSL += " output.gl_Depth = gl_Depth;\n";
1565 }
Jamie Madill46131a32013-06-20 11:55:50 -04001566 }
1567 else
1568 {
1569 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1570 {
1571 const VariableLocation &outputLocation = locationIt->second;
1572 const std::string &variableName = "out_" + outputLocation.name;
1573 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1574 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1575
1576 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1577 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001578 }
1579
1580 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001581 " return output;\n"
1582 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001583
1584 return true;
1585}
1586
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001587std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1588{
1589 std::string varyingHLSL;
1590
Jamie Madillce79dda2013-08-30 13:21:06 -04001591 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001592 {
Jamie Madilla6da33a2013-08-30 13:21:07 -04001593 sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001594 if (varying->registerAssigned())
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001595 {
Jamie Madill139b9092013-08-30 13:21:06 -04001596 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001597 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001598 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill28167c62013-08-30 13:21:10 -04001599 int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
Jamie Madill139b9092013-08-30 13:21:06 -04001600 for (int row = 0; row < variableRows; row++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001601 {
1602 switch (varying->interpolation)
1603 {
Jamie Madill139b9092013-08-30 13:21:06 -04001604 case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break;
1605 case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break;
1606 case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break;
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001607 default: UNREACHABLE();
1608 }
1609
Jamie Madill139b9092013-08-30 13:21:06 -04001610 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
Jamie Madill28167c62013-08-30 13:21:10 -04001611
1612 // matrices within structs are not transposed, hence we do not use the special struct prefix "rm"
1613 std::string typeString = varying->isStruct() ? "_" + varying->structName :
1614 gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001615
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001616 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001617 }
1618 }
1619 }
1620 else UNREACHABLE();
1621 }
1622
1623 return varyingHLSL;
1624}
1625
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001626bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1627{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001628 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629
1630 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001632 if (format != GL_PROGRAM_BINARY_ANGLE)
1633 {
1634 infoLog.append("Invalid program binary format.");
1635 return false;
1636 }
1637
1638 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001639 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001640 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641 {
1642 infoLog.append("Invalid program binary version.");
1643 return false;
1644 }
1645
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001646 int compileFlags = 0;
1647 stream.read(&compileFlags);
1648 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1649 {
1650 infoLog.append("Mismatched compilation flags.");
1651 return false;
1652 }
1653
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001654 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1655 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001656 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001657 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001658 stream.read(&name);
1659 mLinkedAttribute[i].name = name;
1660 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661 }
1662
Al Patrick3f2daa82013-08-07 12:58:57 -07001663 initAttributesByLayout();
1664
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1666 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&mSamplersPS[i].active);
1668 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669
1670 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672 mSamplersPS[i].textureType = (TextureType) textureType;
1673 }
1674
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001675 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001676 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001677 stream.read(&mSamplersVS[i].active);
1678 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679
1680 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682 mSamplersVS[i].textureType = (TextureType) textureType;
1683 }
1684
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001685 stream.read(&mUsedVertexSamplerRange);
1686 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001687 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001688 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001689
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001690 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001691 stream.read(&size);
1692 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693 {
1694 infoLog.append("Invalid program binary.");
1695 return false;
1696 }
1697
1698 mUniforms.resize(size);
1699 for (unsigned int i = 0; i < size; ++i)
1700 {
1701 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001702 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001703 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001704 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001705 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001706
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001707 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001708 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001709 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001710 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001711 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001713 int offset;
1714 int arrayStride;
1715 int matrixStride;
1716 bool isRowMajorMatrix;
1717
1718 stream.read(&offset);
1719 stream.read(&arrayStride);
1720 stream.read(&matrixStride);
1721 stream.read(&isRowMajorMatrix);
1722
1723 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1724
1725 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001726
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001727 stream.read(&mUniforms[i]->psRegisterIndex);
1728 stream.read(&mUniforms[i]->vsRegisterIndex);
1729 stream.read(&mUniforms[i]->registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001730 stream.read(&mUniforms[i]->registerElement);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001731 }
1732
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001733 stream.read(&size);
1734 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735 {
1736 infoLog.append("Invalid program binary.");
1737 return false;
1738 }
1739
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001740 mUniformBlocks.resize(size);
1741 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1742 {
1743 std::string name;
1744 unsigned int elementIndex;
1745 unsigned int dataSize;
1746
1747 stream.read(&name);
1748 stream.read(&elementIndex);
1749 stream.read(&dataSize);
1750
1751 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1752
1753 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1754 stream.read(&uniformBlock.psRegisterIndex);
1755 stream.read(&uniformBlock.vsRegisterIndex);
1756
1757 size_t numMembers;
1758 stream.read(&numMembers);
1759 uniformBlock.memberUniformIndexes.resize(numMembers);
1760 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1761 {
1762 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1763 }
1764 }
1765
1766 stream.read(&size);
1767 if (stream.error())
1768 {
1769 infoLog.append("Invalid program binary.");
1770 return false;
1771 }
1772
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001773 mUniformIndex.resize(size);
1774 for (unsigned int i = 0; i < size; ++i)
1775 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.read(&mUniformIndex[i].name);
1777 stream.read(&mUniformIndex[i].element);
1778 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779 }
1780
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001781 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783
1784 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001787 unsigned int geometryShaderSize;
1788 stream.read(&geometryShaderSize);
1789
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001790 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791
daniel@transgaming.com36038542012-11-28 20:59:26 +00001792 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001793 ptr += sizeof(GUID);
1794
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001795 GUID identifier = mRenderer->getAdapterIdentifier();
1796 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001797 {
1798 infoLog.append("Invalid program binary.");
1799 return false;
1800 }
1801
1802 const char *pixelShaderFunction = ptr;
1803 ptr += pixelShaderSize;
1804
1805 const char *vertexShaderFunction = ptr;
1806 ptr += vertexShaderSize;
1807
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001808 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1809 ptr += geometryShaderSize;
1810
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001811 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001812 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001813 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 {
1815 infoLog.append("Could not create pixel shader.");
1816 return false;
1817 }
1818
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001819 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001820 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001821 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822 {
1823 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001824 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825 mPixelExecutable = NULL;
1826 return false;
1827 }
1828
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001829 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1830 {
1831 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1832 geometryShaderSize, rx::SHADER_GEOMETRY);
1833 if (!mGeometryExecutable)
1834 {
1835 infoLog.append("Could not create geometry shader.");
1836 delete mPixelExecutable;
1837 mPixelExecutable = NULL;
1838 delete mVertexExecutable;
1839 mVertexExecutable = NULL;
1840 return false;
1841 }
1842 }
1843 else
1844 {
1845 mGeometryExecutable = NULL;
1846 }
1847
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001848 return true;
1849}
1850
1851bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1852{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001853 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001855 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001856 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001857 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001858
1859 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1860 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001861 stream.write(mLinkedAttribute[i].type);
1862 stream.write(mLinkedAttribute[i].name);
1863 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001864 }
1865
1866 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1867 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001868 stream.write(mSamplersPS[i].active);
1869 stream.write(mSamplersPS[i].logicalTextureUnit);
1870 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001871 }
1872
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001873 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001874 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001875 stream.write(mSamplersVS[i].active);
1876 stream.write(mSamplersVS[i].logicalTextureUnit);
1877 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001878 }
1879
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001880 stream.write(mUsedVertexSamplerRange);
1881 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001882 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001883 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001884
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001885 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001886 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001887 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001888 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001889
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001890 stream.write(uniform.type);
1891 stream.write(uniform.precision);
1892 stream.write(uniform.name);
1893 stream.write(uniform.arraySize);
1894 stream.write(uniform.blockIndex);
1895
1896 stream.write(uniform.blockInfo.offset);
1897 stream.write(uniform.blockInfo.arrayStride);
1898 stream.write(uniform.blockInfo.matrixStride);
1899 stream.write(uniform.blockInfo.isRowMajorMatrix);
1900
1901 stream.write(uniform.psRegisterIndex);
1902 stream.write(uniform.vsRegisterIndex);
1903 stream.write(uniform.registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001904 stream.write(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001905 }
1906
1907 stream.write(mUniformBlocks.size());
1908 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1909 {
1910 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1911
1912 stream.write(uniformBlock.name);
1913 stream.write(uniformBlock.elementIndex);
1914 stream.write(uniformBlock.dataSize);
1915
1916 stream.write(uniformBlock.memberUniformIndexes.size());
1917 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1918 {
1919 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1920 }
1921
1922 stream.write(uniformBlock.psRegisterIndex);
1923 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001924 }
1925
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001926 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001927 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1928 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001929 stream.write(mUniformIndex[i].name);
1930 stream.write(mUniformIndex[i].element);
1931 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001932 }
1933
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001934 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001935 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001936
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001937 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001938 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001939
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001940 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1941 stream.write(geometryShaderSize);
1942
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001943 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001944
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001945 GLsizei streamLength = stream.length();
1946 const void *streamData = stream.data();
1947
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001948 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001949 if (totalLength > bufSize)
1950 {
1951 if (length)
1952 {
1953 *length = 0;
1954 }
1955
1956 return false;
1957 }
1958
1959 if (binary)
1960 {
1961 char *ptr = (char*) binary;
1962
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001963 memcpy(ptr, streamData, streamLength);
1964 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001965
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001966 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001967 ptr += sizeof(GUID);
1968
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001969 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001970 ptr += pixelShaderSize;
1971
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001972 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001973 ptr += vertexShaderSize;
1974
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001975 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1976 {
1977 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1978 ptr += geometryShaderSize;
1979 }
1980
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001981 ASSERT(ptr - totalLength == binary);
1982 }
1983
1984 if (length)
1985 {
1986 *length = totalLength;
1987 }
1988
1989 return true;
1990}
1991
1992GLint ProgramBinary::getLength()
1993{
1994 GLint length;
1995 if (save(NULL, INT_MAX, &length))
1996 {
1997 return length;
1998 }
1999 else
2000 {
2001 return 0;
2002 }
2003}
2004
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002005bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002006{
2007 if (!fragmentShader || !fragmentShader->isCompiled())
2008 {
2009 return false;
2010 }
2011
2012 if (!vertexShader || !vertexShader->isCompiled())
2013 {
2014 return false;
2015 }
2016
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00002017 mShaderVersion = vertexShader->getShaderVersion();
2018
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002019 std::string pixelHLSL = fragmentShader->getHLSL();
2020 std::string vertexHLSL = vertexShader->getHLSL();
2021
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002022 // Map the varyings to the register file
Jamie Madilla6da33a2013-08-30 13:21:07 -04002023 const sh::ShaderVariable *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002024 int registers = packVaryings(infoLog, packing, fragmentShader);
2025
2026 if (registers < 0)
2027 {
2028 return false;
2029 }
2030
2031 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002032 {
2033 return false;
2034 }
2035
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002036 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002037
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002038 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2039 {
2040 success = false;
2041 }
2042
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002043 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002044 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002045 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002046 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002047
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002048 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2049 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2050 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002051 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2052 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2053 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 +00002054 }
2055
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002056 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2057 {
2058 success = false;
2059 }
2060
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002061 if (success)
2062 {
2063 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
2064 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
2065
2066 if (usesGeometryShader())
2067 {
2068 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2069 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2070 }
2071
2072 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
2073 {
2074 infoLog.append("Failed to create D3D shaders.");
2075 success = false;
2076
2077 delete mVertexExecutable;
2078 mVertexExecutable = NULL;
2079 delete mPixelExecutable;
2080 mPixelExecutable = NULL;
2081 delete mGeometryExecutable;
2082 mGeometryExecutable = NULL;
2083 }
2084 }
2085
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002086 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002087}
2088
2089// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002090bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002091{
2092 unsigned int usedLocations = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002093 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002094
2095 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002096 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002098 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002099 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002100
Jamie Madilleba4eff2013-06-20 11:55:51 -04002101 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002102 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002103 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104
2105 if (rows + location > MAX_VERTEX_ATTRIBS)
2106 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002107 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 +00002108
2109 return false;
2110 }
2111
Jamie Madilleba4eff2013-06-20 11:55:51 -04002112 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002113 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002114 const int rowLocation = location + row;
2115 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2116
2117 // In GLSL 3.00, attribute aliasing produces a link error
2118 // In GLSL 1.00, attribute aliasing is allowed
2119 if (mShaderVersion >= 300)
2120 {
2121 if (!linkedAttribute.name.empty())
2122 {
2123 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2124 return false;
2125 }
2126 }
2127
2128 linkedAttribute = attribute;
2129 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130 }
2131 }
2132 }
2133
2134 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002135 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002136 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002137 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002138 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002139
Jamie Madilleba4eff2013-06-20 11:55:51 -04002140 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002141 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002142 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002143 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2144
2145 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2146 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002147 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002148
2149 return false; // Fail to link
2150 }
2151
Jamie Madilldefb6742013-06-20 11:55:51 -04002152 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002153 }
2154 }
2155
2156 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2157 {
2158 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002159 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002160
2161 for (int r = 0; r < rows; r++)
2162 {
2163 mSemanticIndex[attributeIndex++] = index++;
2164 }
2165 }
2166
Al Patrick3f2daa82013-08-07 12:58:57 -07002167 initAttributesByLayout();
2168
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002169 return true;
2170}
2171
Jamie Madill28167c62013-08-30 13:21:10 -04002172bool 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 +00002173{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002174 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002175 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002176 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002177 return false;
2178 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002179 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002180 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002181 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002182 return false;
2183 }
Jamie Madill28167c62013-08-30 13:21:10 -04002184 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002185 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002186 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04002187 return false;
2188 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002189
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002190 return true;
2191}
2192
2193template <class ShaderVarType>
2194bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
2195{
2196 if (vertexVar.fields.size() != fragmentVar.fields.size())
2197 {
2198 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
2199 return false;
2200 }
2201 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002202 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2203 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002204 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
2205 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002206
2207 if (vertexMember.name != fragmentMember.name)
2208 {
Jamie Madill28167c62013-08-30 13:21:10 -04002209 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
2210 memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002211 return false;
2212 }
2213
Jamie Madill28167c62013-08-30 13:21:10 -04002214 const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002215 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002216 {
2217 return false;
2218 }
2219 }
2220
2221 return true;
2222}
2223
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002224bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2225{
Jamie Madill28167c62013-08-30 13:21:10 -04002226 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002227 {
2228 return false;
2229 }
2230
2231 if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
2232 {
2233 return false;
2234 }
2235
2236 return true;
2237}
2238
Jamie Madill28167c62013-08-30 13:21:10 -04002239bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
2240{
2241 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2242 {
2243 return false;
2244 }
2245
2246 if (vertexVarying.interpolation != fragmentVarying.interpolation)
2247 {
2248 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
2249 return false;
2250 }
2251
2252 if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
2253 {
2254 return false;
2255 }
2256
2257 return true;
2258}
2259
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002260bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
2261{
Jamie Madill28167c62013-08-30 13:21:10 -04002262 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002263 {
2264 return false;
2265 }
2266
2267 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2268 {
2269 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2270 return false;
2271 }
2272
2273 if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
2274 {
2275 return false;
2276 }
2277
2278 return true;
2279}
2280
2281bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002282{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002283 // Check that uniforms defined in the vertex and fragment shaders are identical
2284 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2285 UniformMap linkedUniforms;
2286
2287 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2288 {
2289 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2290 linkedUniforms[vertexUniform.name] = &vertexUniform;
2291 }
2292
2293 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2294 {
2295 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2296 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2297 if (entry != linkedUniforms.end())
2298 {
2299 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04002300 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002301 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002302 {
2303 return false;
2304 }
2305 }
2306 }
2307
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002308 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002309 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002310 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002311 {
2312 return false;
2313 }
2314 }
2315
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002316 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002317 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002318 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002319 {
2320 return false;
2321 }
2322 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002323
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002324 return true;
2325}
2326
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002327int totalRegisterCount(const sh::Uniform &uniform)
2328{
2329 int registerCount = 0;
2330
2331 if (!uniform.fields.empty())
2332 {
2333 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2334 {
2335 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2336 }
2337 }
2338 else
2339 {
2340 registerCount = 1;
2341 }
2342
2343 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2344}
2345
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002346TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
2347{
2348 switch(samplerType)
2349 {
2350 case GL_SAMPLER_2D:
2351 case GL_INT_SAMPLER_2D:
2352 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002353 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002354 return TEXTURE_2D;
2355 case GL_SAMPLER_3D:
2356 case GL_INT_SAMPLER_3D:
2357 case GL_UNSIGNED_INT_SAMPLER_3D:
2358 return TEXTURE_3D;
2359 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002360 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002361 return TEXTURE_CUBE;
2362 case GL_INT_SAMPLER_CUBE:
2363 case GL_UNSIGNED_INT_SAMPLER_CUBE:
2364 //UNIMPLEMENTED();
2365 infoLog.append("Integer cube texture sampling is currently not supported by ANGLE and returns a black color.");
2366 return TEXTURE_CUBE;
2367 case GL_SAMPLER_2D_ARRAY:
2368 case GL_INT_SAMPLER_2D_ARRAY:
2369 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002370 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002371 return TEXTURE_2D_ARRAY;
2372 default: UNREACHABLE();
2373 }
2374
2375 return TEXTURE_2D;
2376}
2377
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002378bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002379{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002380 if (!constant.fields.empty())
2381 {
2382 if (constant.arraySize > 0)
2383 {
2384 unsigned int elementRegisterIndex = constant.registerIndex;
2385
2386 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2387 {
2388 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2389 {
2390 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002391 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madill56093782013-08-30 13:21:11 -04002392 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
2393 elementRegisterIndex, field.elementIndex);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002394 if (!defineUniform(shader, fieldUniform, infoLog))
2395 {
2396 return false;
2397 }
2398 elementRegisterIndex += totalRegisterCount(field);
2399 }
2400 }
2401 }
2402 else
2403 {
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002404 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2405 {
2406 const sh::Uniform &field = constant.fields[fieldIndex];
2407 const std::string &uniformName = constant.name + "." + field.name;
2408
Jamie Madill56093782013-08-30 13:21:11 -04002409 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
2410 field.registerIndex, field.elementIndex);
2411
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002412 fieldUniform.fields = field.fields;
2413
2414 if (!defineUniform(shader, fieldUniform, infoLog))
2415 {
2416 return false;
2417 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002418 }
2419 }
2420
2421 return true;
2422 }
2423
Nicolas Capense6050882013-07-08 10:43:10 -04002424 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002425 {
2426 unsigned int samplerIndex = constant.registerIndex;
2427
2428 do
2429 {
2430 if (shader == GL_VERTEX_SHADER)
2431 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002432 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002433 {
2434 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002435 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002436 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2437 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2438 }
2439 else
2440 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002441 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002442 return false;
2443 }
2444 }
2445 else if (shader == GL_FRAGMENT_SHADER)
2446 {
2447 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2448 {
2449 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002450 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002451 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2452 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2453 }
2454 else
2455 {
2456 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2457 return false;
2458 }
2459 }
2460 else UNREACHABLE();
2461
2462 samplerIndex++;
2463 }
2464 while (samplerIndex < constant.registerIndex + constant.arraySize);
2465 }
2466
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002467 Uniform *uniform = NULL;
2468 GLint location = getUniformLocation(constant.name);
2469
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002470 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002471 {
2472 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002473 }
2474 else
2475 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002476 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
Jamie Madill56093782013-08-30 13:21:11 -04002477 uniform->registerElement = constant.elementIndex;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002478 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002479
2480 if (!uniform)
2481 {
2482 return false;
2483 }
2484
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002485 if (shader == GL_FRAGMENT_SHADER)
2486 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002487 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002488 }
2489 else if (shader == GL_VERTEX_SHADER)
2490 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002491 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002492 }
2493 else UNREACHABLE();
2494
2495 if (location >= 0)
2496 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002497 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002498 }
2499
2500 mUniforms.push_back(uniform);
2501 unsigned int uniformIndex = mUniforms.size() - 1;
2502
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002503 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002504 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002505 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002506 }
2507
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002508 if (shader == GL_VERTEX_SHADER)
2509 {
2510 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2511 {
2512 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2513 return false;
2514 }
2515 }
2516 else if (shader == GL_FRAGMENT_SHADER)
2517 {
2518 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2519 {
2520 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2521 return false;
2522 }
2523 }
2524 else UNREACHABLE();
2525
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002526 return true;
2527}
2528
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002529bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2530{
2531 const char* blockName = vertexInterfaceBlock.name.c_str();
2532
2533 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002534 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002535 {
2536 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2537 return false;
2538 }
2539
2540 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2541 {
2542 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2543 return false;
2544 }
2545
Jamie Madill9060a4e2013-08-12 16:22:57 -07002546 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2547 {
2548 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2549 return false;
2550 }
2551
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002552 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002553 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2554 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002555 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2556 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002557
2558 if (vertexMember.name != fragmentMember.name)
2559 {
Jamie Madill28167c62013-08-30 13:21:10 -04002560 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 +00002561 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2562 return false;
2563 }
2564
Jamie Madill28167c62013-08-30 13:21:10 -04002565 std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002566 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002567 {
2568 return false;
2569 }
2570 }
2571
2572 return true;
2573}
2574
2575bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2576{
2577 // Check that interface blocks defined in the vertex and fragment shaders are identical
2578 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2579 UniformBlockMap linkedUniformBlocks;
2580
2581 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2582 {
2583 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2584 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2585 }
2586
2587 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2588 {
2589 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2590 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2591 if (entry != linkedUniformBlocks.end())
2592 {
2593 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2594 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2595 {
2596 return false;
2597 }
2598 }
2599 }
2600
2601 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2602 {
2603 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2604 {
2605 return false;
2606 }
2607 }
2608
2609 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2610 {
2611 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2612 {
2613 return false;
2614 }
2615 }
2616
2617 return true;
2618}
2619
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002620void 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 +00002621{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002622 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002623 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002624 const sh::InterfaceBlockField &field = fields[uniformIndex];
2625 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002626
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002627 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002628 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002629 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002630 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002631 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002632 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002633 const std::string uniformElementName = fieldName + arrayString(arrayElement);
2634 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002635 }
2636 }
2637 else
2638 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002639 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002640 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002641 }
2642 else
2643 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002644 Uniform *newUniform = new Uniform(field.type, field.precision, fieldName, field.arraySize,
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002645 blockIndex, **blockInfoItr);
2646
2647 // add to uniform list, but not index, since uniform block uniforms have no location
2648 blockUniformIndexes->push_back(mUniforms.size());
2649 mUniforms.push_back(newUniform);
2650 (*blockInfoItr)++;
2651 }
2652 }
2653}
2654
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002655bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2656{
2657 // create uniform block entries if they do not exist
2658 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2659 {
2660 std::vector<unsigned int> blockUniformIndexes;
2661 const unsigned int blockIndex = mUniformBlocks.size();
2662
2663 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002664 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002665 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002666
2667 // create all the uniform blocks
2668 if (interfaceBlock.arraySize > 0)
2669 {
2670 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2671 {
2672 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2673 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2674 mUniformBlocks.push_back(newUniformBlock);
2675 }
2676 }
2677 else
2678 {
2679 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2680 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2681 mUniformBlocks.push_back(newUniformBlock);
2682 }
2683 }
2684
2685 // Assign registers to the uniform blocks
2686 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2687 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2688 ASSERT(blockIndex != GL_INVALID_INDEX);
2689 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2690
2691 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2692 {
2693 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2694 ASSERT(uniformBlock->name == interfaceBlock.name);
2695
2696 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2697 {
2698 return false;
2699 }
2700 }
2701
2702 return true;
2703}
2704
2705bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2706{
2707 if (shader == GL_VERTEX_SHADER)
2708 {
2709 uniformBlock->vsRegisterIndex = registerIndex;
2710 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2711
2712 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2713 {
2714 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2715 return false;
2716 }
2717 }
2718 else if (shader == GL_FRAGMENT_SHADER)
2719 {
2720 uniformBlock->psRegisterIndex = registerIndex;
2721 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2722
2723 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2724 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002725 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002726 return false;
2727 }
2728 }
2729 else UNREACHABLE();
2730
2731 return true;
2732}
2733
Jamie Madilla6da33a2013-08-30 13:21:07 -04002734std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002735{
2736 // for now we only handle point sprite emulation
2737 ASSERT(usesPointSpriteEmulation());
2738 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2739}
2740
Jamie Madilla6da33a2013-08-30 13:21:07 -04002741std::string ProgramBinary::generatePointSpriteHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002742{
2743 ASSERT(registers >= 0);
2744 ASSERT(vertexShader->mUsesPointSize);
2745 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2746
2747 std::string geomHLSL;
2748
2749 std::string varyingSemantic = "TEXCOORD";
2750
2751 std::string fragCoordSemantic;
2752 std::string pointCoordSemantic;
2753
2754 int reservedRegisterIndex = registers;
2755
2756 if (fragmentShader->mUsesFragCoord)
2757 {
2758 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2759 }
2760
2761 if (fragmentShader->mUsesPointCoord)
2762 {
2763 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2764 }
2765
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002766 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2767 "\n"
2768 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002769 "{\n";
2770
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002771 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002772
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002773 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002774
2775 if (fragmentShader->mUsesFragCoord)
2776 {
2777 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2778 }
2779
2780 geomHLSL += " float gl_PointSize : PSIZE;\n"
2781 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002782 "};\n"
2783 "\n"
2784 "struct GS_OUTPUT\n"
2785 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002786
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002787 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002788
2789 if (fragmentShader->mUsesFragCoord)
2790 {
2791 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2792 }
2793
2794 if (fragmentShader->mUsesPointCoord)
2795 {
2796 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2797 }
2798
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002799 geomHLSL += " float gl_PointSize : PSIZE;\n"
2800 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002801 "};\n"
2802 "\n"
2803 "static float2 pointSpriteCorners[] = \n"
2804 "{\n"
2805 " float2( 0.5f, -0.5f),\n"
2806 " float2( 0.5f, 0.5f),\n"
2807 " float2(-0.5f, -0.5f),\n"
2808 " float2(-0.5f, 0.5f)\n"
2809 "};\n"
2810 "\n"
2811 "static float2 pointSpriteTexcoords[] = \n"
2812 "{\n"
2813 " float2(1.0f, 1.0f),\n"
2814 " float2(1.0f, 0.0f),\n"
2815 " float2(0.0f, 1.0f),\n"
2816 " float2(0.0f, 0.0f)\n"
2817 "};\n"
2818 "\n"
2819 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2820 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2821 "\n"
2822 "[maxvertexcount(4)]\n"
2823 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2824 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002825 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2826 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002827
2828 for (int r = 0; r < registers; r++)
2829 {
2830 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2831 }
2832
2833 if (fragmentShader->mUsesFragCoord)
2834 {
2835 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2836 }
2837
2838 geomHLSL += " \n"
2839 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2840 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002841 " 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 +00002842
2843 for (int corner = 0; corner < 4; corner++)
2844 {
2845 geomHLSL += " \n"
2846 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2847
2848 if (fragmentShader->mUsesPointCoord)
2849 {
2850 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2851 }
2852
2853 geomHLSL += " outStream.Append(output);\n";
2854 }
2855
2856 geomHLSL += " \n"
2857 " outStream.RestartStrip();\n"
2858 "}\n";
2859
2860 return geomHLSL;
2861}
2862
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002863// This method needs to match OutputHLSL::decorate
2864std::string ProgramBinary::decorateAttribute(const std::string &name)
2865{
2866 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2867 {
2868 return "_" + name;
2869 }
2870
2871 return name;
2872}
2873
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002874bool ProgramBinary::isValidated() const
2875{
2876 return mValidated;
2877}
2878
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002879void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002880{
2881 // Skip over inactive attributes
2882 unsigned int activeAttribute = 0;
2883 unsigned int attribute;
2884 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2885 {
2886 if (mLinkedAttribute[attribute].name.empty())
2887 {
2888 continue;
2889 }
2890
2891 if (activeAttribute == index)
2892 {
2893 break;
2894 }
2895
2896 activeAttribute++;
2897 }
2898
2899 if (bufsize > 0)
2900 {
2901 const char *string = mLinkedAttribute[attribute].name.c_str();
2902
2903 strncpy(name, string, bufsize);
2904 name[bufsize - 1] = '\0';
2905
2906 if (length)
2907 {
2908 *length = strlen(name);
2909 }
2910 }
2911
2912 *size = 1; // Always a single 'type' instance
2913
2914 *type = mLinkedAttribute[attribute].type;
2915}
2916
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002917GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002918{
2919 int count = 0;
2920
2921 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2922 {
2923 if (!mLinkedAttribute[attributeIndex].name.empty())
2924 {
2925 count++;
2926 }
2927 }
2928
2929 return count;
2930}
2931
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002932GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002933{
2934 int maxLength = 0;
2935
2936 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2937 {
2938 if (!mLinkedAttribute[attributeIndex].name.empty())
2939 {
2940 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2941 }
2942 }
2943
2944 return maxLength;
2945}
2946
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002947void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002948{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002949 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002950
2951 if (bufsize > 0)
2952 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002953 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002954
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002955 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002956 {
2957 string += "[0]";
2958 }
2959
2960 strncpy(name, string.c_str(), bufsize);
2961 name[bufsize - 1] = '\0';
2962
2963 if (length)
2964 {
2965 *length = strlen(name);
2966 }
2967 }
2968
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002969 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002970
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002971 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002972}
2973
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002974GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002975{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002976 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002977}
2978
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002979GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002980{
2981 int maxLength = 0;
2982
2983 unsigned int numUniforms = mUniforms.size();
2984 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2985 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002986 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002987 {
2988 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2989 if (mUniforms[uniformIndex]->isArray())
2990 {
2991 length += 3; // Counting in "[0]".
2992 }
2993 maxLength = std::max(length, maxLength);
2994 }
2995 }
2996
2997 return maxLength;
2998}
2999
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003000GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
3001{
3002 const gl::Uniform& uniform = *mUniforms[index];
3003
3004 switch (pname)
3005 {
3006 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
3007 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00003008 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 +00003009 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003010
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00003011 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
3012 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
3013 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
3014 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00003015
3016 default:
3017 UNREACHABLE();
3018 break;
3019 }
3020 return 0;
3021}
3022
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00003023void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
3024{
3025 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
3026
3027 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3028
3029 if (bufSize > 0)
3030 {
3031 std::string string = uniformBlock.name;
3032
3033 if (uniformBlock.isArrayElement())
3034 {
Jamie Madill63491ea2013-06-06 11:56:45 -04003035 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00003036 }
3037
3038 strncpy(uniformBlockName, string.c_str(), bufSize);
3039 uniformBlockName[bufSize - 1] = '\0';
3040
3041 if (length)
3042 {
3043 *length = strlen(uniformBlockName);
3044 }
3045 }
3046}
3047
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003048void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
3049{
3050 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
3051
3052 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3053
3054 switch (pname)
3055 {
3056 case GL_UNIFORM_BLOCK_DATA_SIZE:
3057 *params = static_cast<GLint>(uniformBlock.dataSize);
3058 break;
3059 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00003060 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003061 break;
3062 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
3063 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
3064 break;
3065 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
3066 {
3067 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
3068 {
3069 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
3070 }
3071 }
3072 break;
3073 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
3074 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
3075 break;
3076 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
3077 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
3078 break;
3079 default: UNREACHABLE();
3080 }
3081}
3082
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00003083GLuint ProgramBinary::getActiveUniformBlockCount() const
3084{
3085 return mUniformBlocks.size();
3086}
3087
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00003088GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
3089{
3090 unsigned int maxLength = 0;
3091
3092 unsigned int numUniformBlocks = mUniformBlocks.size();
3093 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
3094 {
3095 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3096 if (!uniformBlock.name.empty())
3097 {
3098 const unsigned int length = uniformBlock.name.length() + 1;
3099
3100 // Counting in "[0]".
3101 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
3102
3103 maxLength = std::max(length + arrayLength, maxLength);
3104 }
3105 }
3106
3107 return maxLength;
3108}
3109
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003110void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003111{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003112 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003113 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003114 {
3115 mValidated = false;
3116 }
3117 else
3118 {
3119 mValidated = true;
3120 }
3121}
3122
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003123bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003124{
3125 // if any two active samplers in a program are of different types, but refer to the same
3126 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3127 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3128
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00003129 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003130 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003131
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003132 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003133 {
3134 textureUnitType[i] = TEXTURE_UNKNOWN;
3135 }
3136
3137 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3138 {
3139 if (mSamplersPS[i].active)
3140 {
3141 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3142
3143 if (unit >= maxCombinedTextureImageUnits)
3144 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003145 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003146 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003147 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003148 }
3149
3150 return false;
3151 }
3152
3153 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3154 {
3155 if (mSamplersPS[i].textureType != textureUnitType[unit])
3156 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003157 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003158 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003159 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003160 }
3161
3162 return false;
3163 }
3164 }
3165 else
3166 {
3167 textureUnitType[unit] = mSamplersPS[i].textureType;
3168 }
3169 }
3170 }
3171
3172 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3173 {
3174 if (mSamplersVS[i].active)
3175 {
3176 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3177
3178 if (unit >= maxCombinedTextureImageUnits)
3179 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003180 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003181 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003182 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003183 }
3184
3185 return false;
3186 }
3187
3188 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3189 {
3190 if (mSamplersVS[i].textureType != textureUnitType[unit])
3191 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003192 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003193 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003194 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003195 }
3196
3197 return false;
3198 }
3199 }
3200 else
3201 {
3202 textureUnitType[unit] = mSamplersVS[i].textureType;
3203 }
3204 }
3205 }
3206
3207 return true;
3208}
3209
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003210ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3211{
3212}
3213
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003214struct AttributeSorter
3215{
3216 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3217 : originalIndices(semanticIndices)
3218 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003219 }
3220
3221 bool operator()(int a, int b)
3222 {
3223 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3224 }
3225
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003226 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3227};
3228
Al Patrick3f2daa82013-08-07 12:58:57 -07003229void ProgramBinary::initAttributesByLayout()
3230{
3231 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3232 {
3233 mAttributesByLayout[i] = i;
3234 }
3235
3236 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
3237}
3238
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003239void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3240{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003241 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3242
3243 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3244 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003245 oldTranslatedAttributes[i] = attributes[i];
3246 }
3247
3248 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3249 {
Al Patrick3f2daa82013-08-07 12:58:57 -07003250 int oldIndex = mAttributesByLayout[i];
3251 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003252 attributes[i] = oldTranslatedAttributes[oldIndex];
3253 }
3254}
3255
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003256}