blob: bc10e25794e5484687f42c080a4cc08cd9244cd8 [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"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#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
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000039namespace gl_d3d
40{
41 std::string TypeString(GLenum type)
42 {
43 switch (type)
44 {
45 case GL_FLOAT: return "float";
46 case GL_FLOAT_VEC2: return "float2";
47 case GL_FLOAT_VEC3: return "float3";
48 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000049 case GL_INT: return "int";
50 case GL_INT_VEC2: return "int2";
51 case GL_INT_VEC3: return "int3";
52 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000053 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000054 case GL_FLOAT_MAT2: return "float2x2";
55 case GL_FLOAT_MAT3: return "float3x3";
56 case GL_FLOAT_MAT4: return "float4x4";
57 case GL_FLOAT_MAT2x3: return "float2x3";
58 case GL_FLOAT_MAT3x2: return "float3x2";
59 case GL_FLOAT_MAT2x4: return "float2x4";
60 case GL_FLOAT_MAT4x2: return "float4x2";
61 case GL_FLOAT_MAT3x4: return "float3x4";
62 case GL_FLOAT_MAT4x3: return "float4x3";
63 default: UNREACHABLE(); return "invalid-gl-type";
64 }
65 }
66}
67
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000068namespace
69{
70
71unsigned int parseAndStripArrayIndex(std::string* name)
72{
73 unsigned int subscript = GL_INVALID_INDEX;
74
75 // Strip any trailing array operator and retrieve the subscript
76 size_t open = name->find_last_of('[');
77 size_t close = name->find_last_of(']');
78 if (open != std::string::npos && close == name->length() - 1)
79 {
80 subscript = atoi(name->substr(open + 1).c_str());
81 name->erase(open);
82 }
83
84 return subscript;
85}
86
87}
88
daniel@transgaming.comdb019952012-12-20 21:13:32 +000089UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
90 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000091{
92}
93
daniel@transgaming.come87ca002012-07-24 18:30:43 +000094unsigned int ProgramBinary::mCurrentSerial = 1;
95
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000096ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000098 mPixelExecutable = NULL;
99 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000100 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000102 mValidated = false;
103
104 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
105 {
106 mSemanticIndex[index] = -1;
107 }
108
109 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
110 {
111 mSamplersPS[index].active = false;
112 }
113
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000114 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115 {
116 mSamplersVS[index].active = false;
117 }
118
119 mUsedVertexSamplerRange = 0;
120 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000121 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000122 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000123}
124
125ProgramBinary::~ProgramBinary()
126{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000127 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000128 mPixelExecutable = NULL;
129
daniel@transgaming.com95892412012-11-28 20:59:09 +0000130 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000131 mVertexExecutable = NULL;
132
133 delete mGeometryExecutable;
134 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136 while (!mUniforms.empty())
137 {
138 delete mUniforms.back();
139 mUniforms.pop_back();
140 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000141
142 while (!mUniformBlocks.empty())
143 {
144 delete mUniformBlocks.back();
145 mUniformBlocks.pop_back();
146 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000147}
148
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000149unsigned int ProgramBinary::getSerial() const
150{
151 return mSerial;
152}
153
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000154int ProgramBinary::getShaderVersion() const
155{
156 return mShaderVersion;
157}
158
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000159unsigned int ProgramBinary::issueSerial()
160{
161 return mCurrentSerial++;
162}
163
daniel@transgaming.com95892412012-11-28 20:59:09 +0000164rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000165{
166 return mPixelExecutable;
167}
168
daniel@transgaming.com95892412012-11-28 20:59:09 +0000169rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000170{
171 return mVertexExecutable;
172}
173
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000174rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
175{
176 return mGeometryExecutable;
177}
178
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000179GLuint ProgramBinary::getAttributeLocation(const char *name)
180{
181 if (name)
182 {
183 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
184 {
185 if (mLinkedAttribute[index].name == std::string(name))
186 {
187 return index;
188 }
189 }
190 }
191
192 return -1;
193}
194
195int ProgramBinary::getSemanticIndex(int attributeIndex)
196{
197 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
198
199 return mSemanticIndex[attributeIndex];
200}
201
202// Returns one more than the highest sampler index used.
203GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
204{
205 switch (type)
206 {
207 case SAMPLER_PIXEL:
208 return mUsedPixelSamplerRange;
209 case SAMPLER_VERTEX:
210 return mUsedVertexSamplerRange;
211 default:
212 UNREACHABLE();
213 return 0;
214 }
215}
216
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000217bool ProgramBinary::usesPointSize() const
218{
219 return mUsesPointSize;
220}
221
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000222bool ProgramBinary::usesPointSpriteEmulation() const
223{
224 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
225}
226
227bool ProgramBinary::usesGeometryShader() const
228{
229 return usesPointSpriteEmulation();
230}
231
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000232// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
233// index (0-15 for the pixel shader and 0-3 for the vertex shader).
234GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
235{
236 GLint logicalTextureUnit = -1;
237
238 switch (type)
239 {
240 case SAMPLER_PIXEL:
241 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
242
243 if (mSamplersPS[samplerIndex].active)
244 {
245 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
246 }
247 break;
248 case SAMPLER_VERTEX:
249 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
250
251 if (mSamplersVS[samplerIndex].active)
252 {
253 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
254 }
255 break;
256 default: UNREACHABLE();
257 }
258
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000259 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000260 {
261 return logicalTextureUnit;
262 }
263
264 return -1;
265}
266
267// Returns the texture type for a given Direct3D 9 sampler type and
268// index (0-15 for the pixel shader and 0-3 for the vertex shader).
269TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
270{
271 switch (type)
272 {
273 case SAMPLER_PIXEL:
274 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
275 ASSERT(mSamplersPS[samplerIndex].active);
276 return mSamplersPS[samplerIndex].textureType;
277 case SAMPLER_VERTEX:
278 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
279 ASSERT(mSamplersVS[samplerIndex].active);
280 return mSamplersVS[samplerIndex].textureType;
281 default: UNREACHABLE();
282 }
283
284 return TEXTURE_2D;
285}
286
287GLint ProgramBinary::getUniformLocation(std::string name)
288{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000289 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000290
291 unsigned int numUniforms = mUniformIndex.size();
292 for (unsigned int location = 0; location < numUniforms; location++)
293 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000294 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000295 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000296 const int index = mUniformIndex[location].index;
297 const bool isArray = mUniforms[index]->isArray();
298
299 if ((isArray && mUniformIndex[location].element == subscript) ||
300 (subscript == GL_INVALID_INDEX))
301 {
302 return location;
303 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000304 }
305 }
306
307 return -1;
308}
309
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000310GLuint ProgramBinary::getUniformIndex(std::string name)
311{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000312 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000313
314 // The app is not allowed to specify array indices other than 0 for arrays of basic types
315 if (subscript != 0 && subscript != GL_INVALID_INDEX)
316 {
317 return GL_INVALID_INDEX;
318 }
319
320 unsigned int numUniforms = mUniforms.size();
321 for (unsigned int index = 0; index < numUniforms; index++)
322 {
323 if (mUniforms[index]->name == name)
324 {
325 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
326 {
327 return index;
328 }
329 }
330 }
331
332 return GL_INVALID_INDEX;
333}
334
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000335GLuint ProgramBinary::getUniformBlockIndex(std::string name)
336{
337 unsigned int subscript = parseAndStripArrayIndex(&name);
338
339 unsigned int numUniformBlocks = mUniformBlocks.size();
340 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
341 {
342 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
343 if (uniformBlock.name == name)
344 {
345 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
346 if (subscript == uniformBlock.elementIndex || arrayElementZero)
347 {
348 return blockIndex;
349 }
350 }
351 }
352
353 return GL_INVALID_INDEX;
354}
355
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000356UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
357{
358 ASSERT(blockIndex < mUniformBlocks.size());
359 return mUniformBlocks[blockIndex];
360}
361
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000362template <typename T>
363bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000364{
365 if (location < 0 || location >= (int)mUniformIndex.size())
366 {
367 return false;
368 }
369
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000370 const int components = UniformComponentCount(targetUniformType);
371 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
372
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000373 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
374 targetUniform->dirty = true;
375
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000376 int elementCount = targetUniform->elementCount();
377
378 if (elementCount == 1 && count > 1)
379 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
380
381 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
382
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000383 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000384 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000385 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000386
387 for (int i = 0; i < count; i++)
388 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000389 for (int c = 0; c < components; c++)
390 {
391 target[c] = v[c];
392 }
393 for (int c = components; c < 4; c++)
394 {
395 target[c] = 0;
396 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000397 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000398 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000399 }
400 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000401 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000402 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000403 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000404
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000405 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000406 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000407 for (int c = 0; c < components; c++)
408 {
409 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
410 }
411 for (int c = components; c < 4; c++)
412 {
413 boolParams[c] = GL_FALSE;
414 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000415 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000416 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000417 }
418 }
419 else
420 {
421 return false;
422 }
423
424 return true;
425}
426
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000427bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
428{
429 return setUniform(location, count, v, GL_FLOAT);
430}
431
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000432bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
433{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000434 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435}
436
437bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
438{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000439 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000440}
441
442bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
443{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000444 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445}
446
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000447template<typename T>
448void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000449{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000450 int copyWidth = std::min(targetHeight, srcWidth);
451 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452
453 for (int x = 0; x < copyWidth; x++)
454 {
455 for (int y = 0; y < copyHeight; y++)
456 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000457 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000458 }
459 }
460 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000461 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000462 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000463 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000464 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000465 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000466 }
467 }
468 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000469 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000470 {
471 for (int x = 0; x < targetWidth; x++)
472 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000473 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000474 }
475 }
476}
477
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000478template<typename T>
479void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
480{
481 int copyWidth = std::min(targetWidth, srcWidth);
482 int copyHeight = std::min(targetHeight, srcHeight);
483
484 for (int y = 0; y < copyHeight; y++)
485 {
486 for (int x = 0; x < copyWidth; x++)
487 {
488 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
489 }
490 }
491 // clear unfilled right side
492 for (int y = 0; y < copyHeight; y++)
493 {
494 for (int x = copyWidth; x < targetWidth; x++)
495 {
496 target[y * targetWidth + x] = static_cast<T>(0);
497 }
498 }
499 // clear unfilled bottom.
500 for (int y = copyHeight; y < targetHeight; y++)
501 {
502 for (int x = 0; x < targetWidth; x++)
503 {
504 target[y * targetWidth + x] = static_cast<T>(0);
505 }
506 }
507}
508
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000509template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000510bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000511{
512 if (location < 0 || location >= (int)mUniformIndex.size())
513 {
514 return false;
515 }
516
517 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
518 targetUniform->dirty = true;
519
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000520 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000521 {
522 return false;
523 }
524
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000525 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000526
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000527 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000528 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
529
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000530 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000531 const unsigned int targetMatrixStride = (4 * rows);
532 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000533
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000534 for (int i = 0; i < count; i++)
535 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000536 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
537 if (transpose == GL_FALSE)
538 {
539 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
540 }
541 else
542 {
543 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
544 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000545 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000546 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000547 }
548
549 return true;
550}
551
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000552bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000553{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000554 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000555}
556
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000557bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000558{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000559 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560}
561
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000562bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000563{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000564 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000565}
566
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000568{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000569 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000570}
571
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000572bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000573{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000574 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000575}
576
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000577bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000578{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000579 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000580}
581
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000582bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000583{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000584 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000585}
586
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000587bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000588{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000589 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000590}
591
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000592bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000593{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000594 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000595}
596
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000597bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
598{
599 if (location < 0 || location >= (int)mUniformIndex.size())
600 {
601 return false;
602 }
603
604 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
605 targetUniform->dirty = true;
606
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000607 int elementCount = targetUniform->elementCount();
608
609 if (elementCount == 1 && count > 1)
610 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
611
612 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
613
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614 if (targetUniform->type == GL_INT ||
615 targetUniform->type == GL_SAMPLER_2D ||
616 targetUniform->type == GL_SAMPLER_CUBE)
617 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000618 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000619
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000620 for (int i = 0; i < count; i++)
621 {
622 target[0] = v[0];
623 target[1] = 0;
624 target[2] = 0;
625 target[3] = 0;
626 target += 4;
627 v += 1;
628 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629 }
630 else if (targetUniform->type == GL_BOOL)
631 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000632 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000633
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000634 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000635 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000636 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
637 boolParams[1] = GL_FALSE;
638 boolParams[2] = GL_FALSE;
639 boolParams[3] = GL_FALSE;
640 boolParams += 4;
641 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000642 }
643 }
644 else
645 {
646 return false;
647 }
648
649 return true;
650}
651
652bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
653{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000654 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000655}
656
657bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
658{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000659 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000660}
661
662bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
663{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000664 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665}
666
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000667bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
668{
669 return setUniform(location, count, v, GL_UNSIGNED_INT);
670}
671
672bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
673{
674 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
675}
676
677bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
678{
679 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
680}
681
682bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
683{
684 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
685}
686
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000687template <typename T>
688bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000689{
690 if (location < 0 || location >= (int)mUniformIndex.size())
691 {
692 return false;
693 }
694
695 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
696
697 // sized queries -- ensure the provided buffer is large enough
698 if (bufSize)
699 {
700 int requiredBytes = UniformExternalSize(targetUniform->type);
701 if (*bufSize < requiredBytes)
702 {
703 return false;
704 }
705 }
706
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000707 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000708 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000709 const int rows = VariableRowCount(targetUniform->type);
710 const int cols = VariableColumnCount(targetUniform->type);
711 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
712 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000713 else if (uniformType == UniformComponentType(targetUniform->type))
714 {
715 unsigned int size = UniformComponentCount(targetUniform->type);
716 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
717 size * sizeof(T));
718 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000719 else
720 {
721 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000722 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000723 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000724 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000725 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000726 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000727
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000728 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000729 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000730 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000731 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000732 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000733 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000734
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000735 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000736 {
737 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
738
739 for (unsigned int i = 0; i < size; i++)
740 {
741 params[i] = static_cast<T>(floatParams[i]);
742 }
743 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000744 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000745
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000746 case GL_INT:
747 {
748 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
749
750 for (unsigned int i = 0; i < size; i++)
751 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000752 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000753 }
754 }
755 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000756
757 case GL_UNSIGNED_INT:
758 {
759 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000760
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000761 for (unsigned int i = 0; i < size; i++)
762 {
763 params[i] = static_cast<T>(uintParams[i]);
764 }
765 }
766 break;
767
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000768 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000769 }
770 }
771
772 return true;
773}
774
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000775bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
776{
777 return getUniformv(location, bufSize, params, GL_FLOAT);
778}
779
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000780bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
781{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000782 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000783}
784
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000785bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
786{
787 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
788}
789
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000790void ProgramBinary::dirtyAllUniforms()
791{
792 unsigned int numUniforms = mUniforms.size();
793 for (unsigned int index = 0; index < numUniforms; index++)
794 {
795 mUniforms[index]->dirty = true;
796 }
797}
798
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000799// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000800void ProgramBinary::applyUniforms()
801{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000802 // Retrieve sampler uniform values
803 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
804 {
805 Uniform *targetUniform = *ub;
806
807 if (targetUniform->dirty)
808 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000809 if (targetUniform->type == GL_SAMPLER_2D ||
810 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000811 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000812 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000813 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000814
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000815 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000816 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000817 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000818
819 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000820 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000821 unsigned int samplerIndex = firstIndex + i;
822
823 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000824 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000825 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000826 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000827 }
828 }
829 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000830
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000831 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000832 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000833 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000834
835 for (int i = 0; i < count; i++)
836 {
837 unsigned int samplerIndex = firstIndex + i;
838
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000839 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000840 {
841 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000842 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000843 }
844 }
845 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000846 }
847 }
848 }
849
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000850 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000851}
852
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000853bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
854{
855 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
856 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
857
858 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
859 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
860
861 ASSERT(boundBuffers.size() == mUniformBlocks.size());
862
863 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
864 {
865 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
866 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
867
868 ASSERT(uniformBlock && uniformBuffer);
869
870 if (uniformBuffer->size() < uniformBlock->dataSize)
871 {
872 // undefined behaviour
873 return false;
874 }
875
876 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
877
878 if (uniformBlock->isReferencedByVertexShader())
879 {
880 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
881 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
882 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
883 vertexUniformBuffers[registerIndex] = uniformBuffer;
884 }
885
886 if (uniformBlock->isReferencedByFragmentShader())
887 {
888 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
889 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
890 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
891 fragmentUniformBuffers[registerIndex] = uniformBuffer;
892 }
893 }
894
895 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
896}
897
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000898// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
899// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000900int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000901{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000902 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000903
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000904 fragmentShader->resetVaryingsRegisterAssignment();
905
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000906 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
907 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000908 GLenum transposedType = TransposeMatrixType(varying->type);
909 int n = VariableRowCount(transposedType) * varying->size;
910 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000911 bool success = false;
912
913 if (m == 2 || m == 3 || m == 4)
914 {
915 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
916 {
917 bool available = true;
918
919 for (int y = 0; y < n && available; y++)
920 {
921 for (int x = 0; x < m && available; x++)
922 {
923 if (packing[r + y][x])
924 {
925 available = false;
926 }
927 }
928 }
929
930 if (available)
931 {
932 varying->reg = r;
933 varying->col = 0;
934
935 for (int y = 0; y < n; y++)
936 {
937 for (int x = 0; x < m; x++)
938 {
939 packing[r + y][x] = &*varying;
940 }
941 }
942
943 success = true;
944 }
945 }
946
947 if (!success && m == 2)
948 {
949 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
950 {
951 bool available = true;
952
953 for (int y = 0; y < n && available; y++)
954 {
955 for (int x = 2; x < 4 && available; x++)
956 {
957 if (packing[r + y][x])
958 {
959 available = false;
960 }
961 }
962 }
963
964 if (available)
965 {
966 varying->reg = r;
967 varying->col = 2;
968
969 for (int y = 0; y < n; y++)
970 {
971 for (int x = 2; x < 4; x++)
972 {
973 packing[r + y][x] = &*varying;
974 }
975 }
976
977 success = true;
978 }
979 }
980 }
981 }
982 else if (m == 1)
983 {
984 int space[4] = {0};
985
986 for (int y = 0; y < maxVaryingVectors; y++)
987 {
988 for (int x = 0; x < 4; x++)
989 {
990 space[x] += packing[y][x] ? 0 : 1;
991 }
992 }
993
994 int column = 0;
995
996 for (int x = 0; x < 4; x++)
997 {
998 if (space[x] >= n && space[x] < space[column])
999 {
1000 column = x;
1001 }
1002 }
1003
1004 if (space[column] >= n)
1005 {
1006 for (int r = 0; r < maxVaryingVectors; r++)
1007 {
1008 if (!packing[r][column])
1009 {
1010 varying->reg = r;
1011
1012 for (int y = r; y < r + n; y++)
1013 {
1014 packing[y][column] = &*varying;
1015 }
1016
1017 break;
1018 }
1019 }
1020
1021 varying->col = column;
1022
1023 success = true;
1024 }
1025 }
1026 else UNREACHABLE();
1027
1028 if (!success)
1029 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001030 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001031
1032 return -1;
1033 }
1034 }
1035
1036 // Return the number of used registers
1037 int registers = 0;
1038
1039 for (int r = 0; r < maxVaryingVectors; r++)
1040 {
1041 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1042 {
1043 registers++;
1044 }
1045 }
1046
1047 return registers;
1048}
1049
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001050bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1051 std::string& pixelHLSL, std::string& vertexHLSL,
1052 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001053{
1054 if (pixelHLSL.empty() || vertexHLSL.empty())
1055 {
1056 return false;
1057 }
1058
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001059 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1060 bool usesFragColor = fragmentShader->mUsesFragColor;
1061 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001062 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001063 {
1064 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1065 return false;
1066 }
1067
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001068 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001069 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001070 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001071
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001072 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1073
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001074 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1075 // - with a 3.0 context, the output color is copied to channel 0
1076 // - with a 2.0 context, the output color is broadcast to all channels
1077 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1078 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1079
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001080 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001081 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001082 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001083
1084 return false;
1085 }
1086
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001087 vertexShader->resetVaryingsRegisterAssignment();
1088
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001089 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1090 {
1091 bool matched = false;
1092
1093 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1094 {
1095 if (output->name == input->name)
1096 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001097 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001098 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001099 infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001100
1101 return false;
1102 }
1103
1104 output->reg = input->reg;
1105 output->col = input->col;
1106
1107 matched = true;
1108 break;
1109 }
1110 }
1111
1112 if (!matched)
1113 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001114 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001115
1116 return false;
1117 }
1118 }
1119
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001120 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001121 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001122 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001123 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1124
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001125 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1126
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001127 // special varyings that use reserved registers
1128 int reservedRegisterIndex = registers;
1129 std::string fragCoordSemantic;
1130 std::string pointCoordSemantic;
1131
1132 if (fragmentShader->mUsesFragCoord)
1133 {
1134 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1135 }
1136
1137 if (fragmentShader->mUsesPointCoord)
1138 {
1139 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1140 // In DX11 we compute this in the GS.
1141 if (shaderModel == 3)
1142 {
1143 pointCoordSemantic = "TEXCOORD0";
1144 }
1145 else if (shaderModel >= 4)
1146 {
1147 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1148 }
1149 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001150
1151 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001152 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001153
1154 int semanticIndex = 0;
1155 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1156 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001157 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001158 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1159
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001160 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001161 }
1162
1163 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001164 "\n"
1165 "struct VS_OUTPUT\n"
1166 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001167
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001168 if (shaderModel < 4)
1169 {
1170 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1171 }
1172
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001173 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001174
1175 if (fragmentShader->mUsesFragCoord)
1176 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001177 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001178 }
1179
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001180 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001181 {
1182 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1183 }
1184
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001185 if (shaderModel >= 4)
1186 {
1187 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1188 }
1189
1190 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001191 "\n"
1192 "VS_OUTPUT main(VS_INPUT input)\n"
1193 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001194
1195 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1196 {
1197 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1198
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001199 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001200 {
1201 vertexHLSL += "transpose";
1202 }
1203
1204 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1205 }
1206
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001207 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1208 {
1209 vertexHLSL += "\n"
1210 " dx_initConstantBuffers();\n";
1211 }
1212
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001213 if (shaderModel >= 4)
1214 {
1215 vertexHLSL += "\n"
1216 " gl_main();\n"
1217 "\n"
1218 " VS_OUTPUT output;\n"
1219 " output.gl_Position.x = gl_Position.x;\n"
1220 " output.gl_Position.y = -gl_Position.y;\n"
1221 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1222 " output.gl_Position.w = gl_Position.w;\n";
1223 }
1224 else
1225 {
1226 vertexHLSL += "\n"
1227 " gl_main();\n"
1228 "\n"
1229 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001230 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1231 " 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 +00001232 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1233 " output.gl_Position.w = gl_Position.w;\n";
1234 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001235
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001236 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001237 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001238 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239 }
1240
1241 if (fragmentShader->mUsesFragCoord)
1242 {
1243 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1244 }
1245
1246 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1247 {
1248 if (varying->reg >= 0)
1249 {
1250 for (int i = 0; i < varying->size; i++)
1251 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001252 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001253
1254 for (int j = 0; j < rows; j++)
1255 {
1256 int r = varying->reg + i * rows + j;
1257 vertexHLSL += " output.v" + str(r);
1258
1259 bool sharedRegister = false; // Register used by multiple varyings
1260
1261 for (int x = 0; x < 4; x++)
1262 {
1263 if (packing[r][x] && packing[r][x] != packing[r][0])
1264 {
1265 sharedRegister = true;
1266 break;
1267 }
1268 }
1269
1270 if(sharedRegister)
1271 {
1272 vertexHLSL += ".";
1273
1274 for (int x = 0; x < 4; x++)
1275 {
1276 if (packing[r][x] == &*varying)
1277 {
1278 switch(x)
1279 {
1280 case 0: vertexHLSL += "x"; break;
1281 case 1: vertexHLSL += "y"; break;
1282 case 2: vertexHLSL += "z"; break;
1283 case 3: vertexHLSL += "w"; break;
1284 }
1285 }
1286 }
1287 }
1288
1289 vertexHLSL += " = " + varying->name;
1290
1291 if (varying->array)
1292 {
1293 vertexHLSL += "[" + str(i) + "]";
1294 }
1295
1296 if (rows > 1)
1297 {
1298 vertexHLSL += "[" + str(j) + "]";
1299 }
1300
1301 vertexHLSL += ";\n";
1302 }
1303 }
1304 }
1305 }
1306
1307 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001308 " return output;\n"
1309 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310
1311 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001312 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001313
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001314 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001315
1316 if (fragmentShader->mUsesFragCoord)
1317 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001318 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001319 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001320
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001321 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1322 {
1323 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1324 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001325
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001326 // Must consume the PSIZE element if the geometry shader is not active
1327 // We won't know if we use a GS until we draw
1328 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1329 {
1330 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1331 }
1332
1333 if (fragmentShader->mUsesFragCoord)
1334 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001335 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001336 {
1337 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1338 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001339 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001340 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001341 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1342 }
1343 }
1344
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001345 pixelHLSL += "};\n"
1346 "\n"
1347 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001348 "{\n";
1349
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001350 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001351 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001352 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001353 }
1354
1355 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001356 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001357
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358 if (fragmentShader->mUsesFrontFacing)
1359 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001360 if (shaderModel >= 4)
1361 {
1362 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1363 "{\n";
1364 }
1365 else
1366 {
1367 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1368 "{\n";
1369 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001370 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001371 else
1372 {
1373 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1374 "{\n";
1375 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001376
1377 if (fragmentShader->mUsesFragCoord)
1378 {
1379 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1380
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001381 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001382 {
1383 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1384 " gl_FragCoord.y = input.dx_VPos.y;\n";
1385 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001386 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001387 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001388 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001389 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001390 }
1391 else
1392 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001393 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1394 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1395 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001396 }
1397
daniel@transgaming.com12985182012-12-20 20:56:31 +00001398 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001399 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001400 }
1401
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001402 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001403 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001404 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1405 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001406 }
1407
1408 if (fragmentShader->mUsesFrontFacing)
1409 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001410 if (shaderModel <= 3)
1411 {
1412 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1413 }
1414 else
1415 {
1416 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1417 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001418 }
1419
1420 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1421 {
1422 if (varying->reg >= 0)
1423 {
1424 for (int i = 0; i < varying->size; i++)
1425 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001426 GLenum transposedType = TransposeMatrixType(varying->type);
1427 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001428 for (int j = 0; j < rows; j++)
1429 {
1430 std::string n = str(varying->reg + i * rows + j);
1431 pixelHLSL += " " + varying->name;
1432
1433 if (varying->array)
1434 {
1435 pixelHLSL += "[" + str(i) + "]";
1436 }
1437
1438 if (rows > 1)
1439 {
1440 pixelHLSL += "[" + str(j) + "]";
1441 }
1442
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001443 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001444 {
1445 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1446 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1447 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1448 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1449 default: UNREACHABLE();
1450 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451 }
1452 }
1453 }
1454 else UNREACHABLE();
1455 }
1456
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001457 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1458 {
1459 pixelHLSL += "\n"
1460 " dx_initConstantBuffers();\n";
1461 }
1462
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001463 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001464 " gl_main();\n"
1465 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001466 " PS_OUTPUT output;\n";
1467
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001468 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001469 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001470 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001471
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001472 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001473 }
1474
1475 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001476 " return output;\n"
1477 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001478
1479 return true;
1480}
1481
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001482std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1483{
1484 std::string varyingHLSL;
1485
1486 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1487 {
1488 if (varying->reg >= 0)
1489 {
1490 for (int i = 0; i < varying->size; i++)
1491 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001492 GLenum transposedType = TransposeMatrixType(varying->type);
1493 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001494 for (int j = 0; j < rows; j++)
1495 {
1496 switch (varying->interpolation)
1497 {
1498 case Smooth: varyingHLSL += " "; break;
1499 case Flat: varyingHLSL += " nointerpolation "; break;
1500 case Centroid: varyingHLSL += " centroid "; break;
1501 default: UNREACHABLE();
1502 }
1503
1504 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001505 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001506
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001507 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001508 }
1509 }
1510 }
1511 else UNREACHABLE();
1512 }
1513
1514 return varyingHLSL;
1515}
1516
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001517bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1518{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001519 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001520
1521 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001522 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001523 if (format != GL_PROGRAM_BINARY_ANGLE)
1524 {
1525 infoLog.append("Invalid program binary format.");
1526 return false;
1527 }
1528
1529 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001530 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001531 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001532 {
1533 infoLog.append("Invalid program binary version.");
1534 return false;
1535 }
1536
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001537 int compileFlags = 0;
1538 stream.read(&compileFlags);
1539 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1540 {
1541 infoLog.append("Mismatched compilation flags.");
1542 return false;
1543 }
1544
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001545 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1546 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001547 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001548 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001549 stream.read(&name);
1550 mLinkedAttribute[i].name = name;
1551 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001552 }
1553
1554 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1555 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001556 stream.read(&mSamplersPS[i].active);
1557 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001558
1559 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001560 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001561 mSamplersPS[i].textureType = (TextureType) textureType;
1562 }
1563
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001564 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001566 stream.read(&mSamplersVS[i].active);
1567 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001568
1569 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001570 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571 mSamplersVS[i].textureType = (TextureType) textureType;
1572 }
1573
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001574 stream.read(&mUsedVertexSamplerRange);
1575 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001576 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001577 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001579 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001580 stream.read(&size);
1581 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001582 {
1583 infoLog.append("Invalid program binary.");
1584 return false;
1585 }
1586
1587 mUniforms.resize(size);
1588 for (unsigned int i = 0; i < size; ++i)
1589 {
1590 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001591 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001592 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001593 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001594 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001595
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001596 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001597 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001598 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001600 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001602 int offset;
1603 int arrayStride;
1604 int matrixStride;
1605 bool isRowMajorMatrix;
1606
1607 stream.read(&offset);
1608 stream.read(&arrayStride);
1609 stream.read(&matrixStride);
1610 stream.read(&isRowMajorMatrix);
1611
1612 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1613
1614 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001615
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001616 stream.read(&mUniforms[i]->psRegisterIndex);
1617 stream.read(&mUniforms[i]->vsRegisterIndex);
1618 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001619 }
1620
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001621 stream.read(&size);
1622 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623 {
1624 infoLog.append("Invalid program binary.");
1625 return false;
1626 }
1627
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001628 mUniformBlocks.resize(size);
1629 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1630 {
1631 std::string name;
1632 unsigned int elementIndex;
1633 unsigned int dataSize;
1634
1635 stream.read(&name);
1636 stream.read(&elementIndex);
1637 stream.read(&dataSize);
1638
1639 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1640
1641 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1642 stream.read(&uniformBlock.psRegisterIndex);
1643 stream.read(&uniformBlock.vsRegisterIndex);
1644
1645 size_t numMembers;
1646 stream.read(&numMembers);
1647 uniformBlock.memberUniformIndexes.resize(numMembers);
1648 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1649 {
1650 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1651 }
1652 }
1653
1654 stream.read(&size);
1655 if (stream.error())
1656 {
1657 infoLog.append("Invalid program binary.");
1658 return false;
1659 }
1660
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661 mUniformIndex.resize(size);
1662 for (unsigned int i = 0; i < size; ++i)
1663 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 stream.read(&mUniformIndex[i].name);
1665 stream.read(&mUniformIndex[i].element);
1666 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667 }
1668
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001670 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671
1672 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001675 unsigned int geometryShaderSize;
1676 stream.read(&geometryShaderSize);
1677
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679
daniel@transgaming.com36038542012-11-28 20:59:26 +00001680 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001681 ptr += sizeof(GUID);
1682
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001683 GUID identifier = mRenderer->getAdapterIdentifier();
1684 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001685 {
1686 infoLog.append("Invalid program binary.");
1687 return false;
1688 }
1689
1690 const char *pixelShaderFunction = ptr;
1691 ptr += pixelShaderSize;
1692
1693 const char *vertexShaderFunction = ptr;
1694 ptr += vertexShaderSize;
1695
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001696 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1697 ptr += geometryShaderSize;
1698
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001699 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001700 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001701 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001702 {
1703 infoLog.append("Could not create pixel shader.");
1704 return false;
1705 }
1706
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001707 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001708 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001709 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710 {
1711 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001712 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001713 mPixelExecutable = NULL;
1714 return false;
1715 }
1716
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001717 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1718 {
1719 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1720 geometryShaderSize, rx::SHADER_GEOMETRY);
1721 if (!mGeometryExecutable)
1722 {
1723 infoLog.append("Could not create geometry shader.");
1724 delete mPixelExecutable;
1725 mPixelExecutable = NULL;
1726 delete mVertexExecutable;
1727 mVertexExecutable = NULL;
1728 return false;
1729 }
1730 }
1731 else
1732 {
1733 mGeometryExecutable = NULL;
1734 }
1735
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736 return true;
1737}
1738
1739bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1740{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001741 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001742
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001744 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001745 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746
1747 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1748 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001749 stream.write(mLinkedAttribute[i].type);
1750 stream.write(mLinkedAttribute[i].name);
1751 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752 }
1753
1754 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1755 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001756 stream.write(mSamplersPS[i].active);
1757 stream.write(mSamplersPS[i].logicalTextureUnit);
1758 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001759 }
1760
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001761 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001763 stream.write(mSamplersVS[i].active);
1764 stream.write(mSamplersVS[i].logicalTextureUnit);
1765 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001766 }
1767
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001768 stream.write(mUsedVertexSamplerRange);
1769 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001770 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001771 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001773 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001774 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001776 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001778 stream.write(uniform.type);
1779 stream.write(uniform.precision);
1780 stream.write(uniform.name);
1781 stream.write(uniform.arraySize);
1782 stream.write(uniform.blockIndex);
1783
1784 stream.write(uniform.blockInfo.offset);
1785 stream.write(uniform.blockInfo.arrayStride);
1786 stream.write(uniform.blockInfo.matrixStride);
1787 stream.write(uniform.blockInfo.isRowMajorMatrix);
1788
1789 stream.write(uniform.psRegisterIndex);
1790 stream.write(uniform.vsRegisterIndex);
1791 stream.write(uniform.registerCount);
1792 }
1793
1794 stream.write(mUniformBlocks.size());
1795 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1796 {
1797 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1798
1799 stream.write(uniformBlock.name);
1800 stream.write(uniformBlock.elementIndex);
1801 stream.write(uniformBlock.dataSize);
1802
1803 stream.write(uniformBlock.memberUniformIndexes.size());
1804 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1805 {
1806 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1807 }
1808
1809 stream.write(uniformBlock.psRegisterIndex);
1810 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001811 }
1812
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001813 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1815 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(mUniformIndex[i].name);
1817 stream.write(mUniformIndex[i].element);
1818 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819 }
1820
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001821 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001822 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001824 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001826
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001827 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1828 stream.write(geometryShaderSize);
1829
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001830 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001832 GLsizei streamLength = stream.length();
1833 const void *streamData = stream.data();
1834
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001835 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001836 if (totalLength > bufSize)
1837 {
1838 if (length)
1839 {
1840 *length = 0;
1841 }
1842
1843 return false;
1844 }
1845
1846 if (binary)
1847 {
1848 char *ptr = (char*) binary;
1849
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001850 memcpy(ptr, streamData, streamLength);
1851 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001852
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001853 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854 ptr += sizeof(GUID);
1855
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001856 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857 ptr += pixelShaderSize;
1858
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001859 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001860 ptr += vertexShaderSize;
1861
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001862 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1863 {
1864 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1865 ptr += geometryShaderSize;
1866 }
1867
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001868 ASSERT(ptr - totalLength == binary);
1869 }
1870
1871 if (length)
1872 {
1873 *length = totalLength;
1874 }
1875
1876 return true;
1877}
1878
1879GLint ProgramBinary::getLength()
1880{
1881 GLint length;
1882 if (save(NULL, INT_MAX, &length))
1883 {
1884 return length;
1885 }
1886 else
1887 {
1888 return 0;
1889 }
1890}
1891
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001892bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001893{
1894 if (!fragmentShader || !fragmentShader->isCompiled())
1895 {
1896 return false;
1897 }
1898
1899 if (!vertexShader || !vertexShader->isCompiled())
1900 {
1901 return false;
1902 }
1903
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001904 mShaderVersion = vertexShader->getShaderVersion();
1905
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001906 std::string pixelHLSL = fragmentShader->getHLSL();
1907 std::string vertexHLSL = vertexShader->getHLSL();
1908
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001909 // Map the varyings to the register file
1910 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1911 int registers = packVaryings(infoLog, packing, fragmentShader);
1912
1913 if (registers < 0)
1914 {
1915 return false;
1916 }
1917
1918 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001919 {
1920 return false;
1921 }
1922
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001923 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001924 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1925 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001926
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001927 if (usesGeometryShader())
1928 {
1929 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1930 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1931 }
1932
1933 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001934 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001935 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001936 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001937
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001938 delete mVertexExecutable;
1939 mVertexExecutable = NULL;
1940 delete mPixelExecutable;
1941 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001942 delete mGeometryExecutable;
1943 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001944 }
1945
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001946 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1947 {
1948 success = false;
1949 }
1950
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001951 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001952 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001953 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001954 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001955
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001956 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1957 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1958 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001959 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1960 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1961 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 +00001962 }
1963
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001964 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1965 {
1966 success = false;
1967 }
1968
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001969 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001970}
1971
1972// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001973bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001974{
1975 unsigned int usedLocations = 0;
1976
1977 // Link attributes that have a binding location
1978 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1979 {
1980 int location = attributeBindings.getAttributeBinding(attribute->name);
1981
1982 if (location != -1) // Set by glBindAttribLocation
1983 {
1984 if (!mLinkedAttribute[location].name.empty())
1985 {
1986 // Multiple active attributes bound to the same location; not an error
1987 }
1988
1989 mLinkedAttribute[location] = *attribute;
1990
1991 int rows = VariableRowCount(attribute->type);
1992
1993 if (rows + location > MAX_VERTEX_ATTRIBS)
1994 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001995 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 +00001996
1997 return false;
1998 }
1999
2000 for (int i = 0; i < rows; i++)
2001 {
2002 usedLocations |= 1 << (location + i);
2003 }
2004 }
2005 }
2006
2007 // Link attributes that don't have a binding location
2008 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2009 {
2010 int location = attributeBindings.getAttributeBinding(attribute->name);
2011
2012 if (location == -1) // Not set by glBindAttribLocation
2013 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002014 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002015 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2016
2017 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2018 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002019 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002020
2021 return false; // Fail to link
2022 }
2023
2024 mLinkedAttribute[availableIndex] = *attribute;
2025 }
2026 }
2027
2028 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2029 {
2030 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002031 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002032
2033 for (int r = 0; r < rows; r++)
2034 {
2035 mSemanticIndex[attributeIndex++] = index++;
2036 }
2037 }
2038
2039 return true;
2040}
2041
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002042bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2043{
2044 if (vertexUniform.type != fragmentUniform.type)
2045 {
2046 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2047 return false;
2048 }
2049 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2050 {
2051 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2052 return false;
2053 }
2054 else if (vertexUniform.precision != fragmentUniform.precision)
2055 {
2056 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2057 return false;
2058 }
2059 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2060 {
2061 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2062 }
2063
2064 const unsigned int numMembers = vertexUniform.fields.size();
2065 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2066 {
2067 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2068 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2069
2070 if (vertexMember.name != fragmentMember.name)
2071 {
2072 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2073 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2074 return false;
2075 }
2076
2077 const std::string memberName = uniformName + "." + vertexUniform.name;
2078 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2079 {
2080 return false;
2081 }
2082 }
2083
2084 return true;
2085}
2086
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002087bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002088{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002089 // Check that uniforms defined in the vertex and fragment shaders are identical
2090 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2091 UniformMap linkedUniforms;
2092
2093 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2094 {
2095 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2096 linkedUniforms[vertexUniform.name] = &vertexUniform;
2097 }
2098
2099 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2100 {
2101 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2102 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2103 if (entry != linkedUniforms.end())
2104 {
2105 const sh::Uniform &vertexUniform = *entry->second;
2106 const std::string &uniformName = "uniform " + vertexUniform.name;
2107 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2108 {
2109 return false;
2110 }
2111 }
2112 }
2113
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002114 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002115 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002116 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002117 {
2118 return false;
2119 }
2120 }
2121
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002122 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002123 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002124 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002125 {
2126 return false;
2127 }
2128 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002129
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130 return true;
2131}
2132
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002133int totalRegisterCount(const sh::Uniform &uniform)
2134{
2135 int registerCount = 0;
2136
2137 if (!uniform.fields.empty())
2138 {
2139 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2140 {
2141 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2142 }
2143 }
2144 else
2145 {
2146 registerCount = 1;
2147 }
2148
2149 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2150}
2151
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002152bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002153{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002154 if (!constant.fields.empty())
2155 {
2156 if (constant.arraySize > 0)
2157 {
2158 unsigned int elementRegisterIndex = constant.registerIndex;
2159
2160 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2161 {
2162 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2163 {
2164 const sh::Uniform &field = constant.fields[fieldIndex];
2165 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2166 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2167 if (!defineUniform(shader, fieldUniform, infoLog))
2168 {
2169 return false;
2170 }
2171 elementRegisterIndex += totalRegisterCount(field);
2172 }
2173 }
2174 }
2175 else
2176 {
2177 unsigned int fieldRegisterIndex = constant.registerIndex;
2178
2179 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2180 {
2181 const sh::Uniform &field = constant.fields[fieldIndex];
2182 const std::string &uniformName = constant.name + "." + field.name;
2183
2184 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2185 fieldUniform.fields = field.fields;
2186
2187 if (!defineUniform(shader, fieldUniform, infoLog))
2188 {
2189 return false;
2190 }
2191 fieldRegisterIndex += totalRegisterCount(field);
2192 }
2193 }
2194
2195 return true;
2196 }
2197
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002198 if (constant.type == GL_SAMPLER_2D ||
2199 constant.type == GL_SAMPLER_CUBE)
2200 {
2201 unsigned int samplerIndex = constant.registerIndex;
2202
2203 do
2204 {
2205 if (shader == GL_VERTEX_SHADER)
2206 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002207 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002208 {
2209 mSamplersVS[samplerIndex].active = true;
2210 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2211 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2212 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2213 }
2214 else
2215 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002216 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002217 return false;
2218 }
2219 }
2220 else if (shader == GL_FRAGMENT_SHADER)
2221 {
2222 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2223 {
2224 mSamplersPS[samplerIndex].active = true;
2225 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2226 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2227 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2228 }
2229 else
2230 {
2231 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2232 return false;
2233 }
2234 }
2235 else UNREACHABLE();
2236
2237 samplerIndex++;
2238 }
2239 while (samplerIndex < constant.registerIndex + constant.arraySize);
2240 }
2241
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002242 Uniform *uniform = NULL;
2243 GLint location = getUniformLocation(constant.name);
2244
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002245 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002246 {
2247 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002248 }
2249 else
2250 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002251 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002252 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002253
2254 if (!uniform)
2255 {
2256 return false;
2257 }
2258
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002259 if (shader == GL_FRAGMENT_SHADER)
2260 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002261 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002262 }
2263 else if (shader == GL_VERTEX_SHADER)
2264 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002265 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002266 }
2267 else UNREACHABLE();
2268
2269 if (location >= 0)
2270 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002271 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002272 }
2273
2274 mUniforms.push_back(uniform);
2275 unsigned int uniformIndex = mUniforms.size() - 1;
2276
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002277 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002278 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002279 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002280 }
2281
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002282 if (shader == GL_VERTEX_SHADER)
2283 {
2284 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2285 {
2286 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2287 return false;
2288 }
2289 }
2290 else if (shader == GL_FRAGMENT_SHADER)
2291 {
2292 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2293 {
2294 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2295 return false;
2296 }
2297 }
2298 else UNREACHABLE();
2299
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002300 return true;
2301}
2302
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002303bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2304{
2305 const char* blockName = vertexInterfaceBlock.name.c_str();
2306
2307 // validate blocks for the same member types
2308 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2309 {
2310 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2311 return false;
2312 }
2313
2314 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2315 {
2316 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2317 return false;
2318 }
2319
2320 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2321 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2322 {
2323 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2324 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2325
2326 if (vertexMember.name != fragmentMember.name)
2327 {
2328 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2329 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2330 return false;
2331 }
2332
2333 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2334 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2335 {
2336 return false;
2337 }
2338 }
2339
2340 return true;
2341}
2342
2343bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2344{
2345 // Check that interface blocks defined in the vertex and fragment shaders are identical
2346 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2347 UniformBlockMap linkedUniformBlocks;
2348
2349 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2350 {
2351 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2352 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2353 }
2354
2355 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2356 {
2357 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2358 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2359 if (entry != linkedUniformBlocks.end())
2360 {
2361 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2362 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2363 {
2364 return false;
2365 }
2366 }
2367 }
2368
2369 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2370 {
2371 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2372 {
2373 return false;
2374 }
2375 }
2376
2377 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2378 {
2379 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2380 {
2381 return false;
2382 }
2383 }
2384
2385 return true;
2386}
2387
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002388void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2389{
2390 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2391 {
2392 const sh::Uniform &uniform = uniforms[uniformIndex];
2393
2394 if (!uniform.fields.empty())
2395 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002396 if (uniform.arraySize > 0)
2397 {
2398 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2399 {
2400 const std::string uniformElementName = uniform.name + "[" + str(arrayElement) + "]";
2401 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2402 }
2403 }
2404 else
2405 {
2406 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2407 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002408 }
2409 else
2410 {
2411 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2412 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2413 blockIndex, **blockInfoItr);
2414
2415 // add to uniform list, but not index, since uniform block uniforms have no location
2416 blockUniformIndexes->push_back(mUniforms.size());
2417 mUniforms.push_back(newUniform);
2418 (*blockInfoItr)++;
2419 }
2420 }
2421}
2422
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002423bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2424{
2425 // create uniform block entries if they do not exist
2426 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2427 {
2428 std::vector<unsigned int> blockUniformIndexes;
2429 const unsigned int blockIndex = mUniformBlocks.size();
2430
2431 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002432 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2433 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002434
2435 // create all the uniform blocks
2436 if (interfaceBlock.arraySize > 0)
2437 {
2438 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2439 {
2440 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2441 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2442 mUniformBlocks.push_back(newUniformBlock);
2443 }
2444 }
2445 else
2446 {
2447 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2448 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2449 mUniformBlocks.push_back(newUniformBlock);
2450 }
2451 }
2452
2453 // Assign registers to the uniform blocks
2454 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2455 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2456 ASSERT(blockIndex != GL_INVALID_INDEX);
2457 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2458
2459 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2460 {
2461 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2462 ASSERT(uniformBlock->name == interfaceBlock.name);
2463
2464 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2465 {
2466 return false;
2467 }
2468 }
2469
2470 return true;
2471}
2472
2473bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2474{
2475 if (shader == GL_VERTEX_SHADER)
2476 {
2477 uniformBlock->vsRegisterIndex = registerIndex;
2478 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2479
2480 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2481 {
2482 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2483 return false;
2484 }
2485 }
2486 else if (shader == GL_FRAGMENT_SHADER)
2487 {
2488 uniformBlock->psRegisterIndex = registerIndex;
2489 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2490
2491 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2492 {
2493 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2494 return false;
2495 }
2496 }
2497 else UNREACHABLE();
2498
2499 return true;
2500}
2501
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002502std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2503{
2504 // for now we only handle point sprite emulation
2505 ASSERT(usesPointSpriteEmulation());
2506 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2507}
2508
2509std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2510{
2511 ASSERT(registers >= 0);
2512 ASSERT(vertexShader->mUsesPointSize);
2513 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2514
2515 std::string geomHLSL;
2516
2517 std::string varyingSemantic = "TEXCOORD";
2518
2519 std::string fragCoordSemantic;
2520 std::string pointCoordSemantic;
2521
2522 int reservedRegisterIndex = registers;
2523
2524 if (fragmentShader->mUsesFragCoord)
2525 {
2526 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2527 }
2528
2529 if (fragmentShader->mUsesPointCoord)
2530 {
2531 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2532 }
2533
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002534 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2535 "\n"
2536 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002537 "{\n";
2538
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002539 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002540
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002541 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002542
2543 if (fragmentShader->mUsesFragCoord)
2544 {
2545 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2546 }
2547
2548 geomHLSL += " float gl_PointSize : PSIZE;\n"
2549 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002550 "};\n"
2551 "\n"
2552 "struct GS_OUTPUT\n"
2553 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002554
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002555 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002556
2557 if (fragmentShader->mUsesFragCoord)
2558 {
2559 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2560 }
2561
2562 if (fragmentShader->mUsesPointCoord)
2563 {
2564 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2565 }
2566
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002567 geomHLSL += " float gl_PointSize : PSIZE;\n"
2568 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002569 "};\n"
2570 "\n"
2571 "static float2 pointSpriteCorners[] = \n"
2572 "{\n"
2573 " float2( 0.5f, -0.5f),\n"
2574 " float2( 0.5f, 0.5f),\n"
2575 " float2(-0.5f, -0.5f),\n"
2576 " float2(-0.5f, 0.5f)\n"
2577 "};\n"
2578 "\n"
2579 "static float2 pointSpriteTexcoords[] = \n"
2580 "{\n"
2581 " float2(1.0f, 1.0f),\n"
2582 " float2(1.0f, 0.0f),\n"
2583 " float2(0.0f, 1.0f),\n"
2584 " float2(0.0f, 0.0f)\n"
2585 "};\n"
2586 "\n"
2587 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2588 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2589 "\n"
2590 "[maxvertexcount(4)]\n"
2591 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2592 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002593 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2594 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002595
2596 for (int r = 0; r < registers; r++)
2597 {
2598 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2599 }
2600
2601 if (fragmentShader->mUsesFragCoord)
2602 {
2603 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2604 }
2605
2606 geomHLSL += " \n"
2607 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2608 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002609 " 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 +00002610
2611 for (int corner = 0; corner < 4; corner++)
2612 {
2613 geomHLSL += " \n"
2614 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2615
2616 if (fragmentShader->mUsesPointCoord)
2617 {
2618 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2619 }
2620
2621 geomHLSL += " outStream.Append(output);\n";
2622 }
2623
2624 geomHLSL += " \n"
2625 " outStream.RestartStrip();\n"
2626 "}\n";
2627
2628 return geomHLSL;
2629}
2630
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002631// This method needs to match OutputHLSL::decorate
2632std::string ProgramBinary::decorateAttribute(const std::string &name)
2633{
2634 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2635 {
2636 return "_" + name;
2637 }
2638
2639 return name;
2640}
2641
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002642bool ProgramBinary::isValidated() const
2643{
2644 return mValidated;
2645}
2646
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002647void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002648{
2649 // Skip over inactive attributes
2650 unsigned int activeAttribute = 0;
2651 unsigned int attribute;
2652 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2653 {
2654 if (mLinkedAttribute[attribute].name.empty())
2655 {
2656 continue;
2657 }
2658
2659 if (activeAttribute == index)
2660 {
2661 break;
2662 }
2663
2664 activeAttribute++;
2665 }
2666
2667 if (bufsize > 0)
2668 {
2669 const char *string = mLinkedAttribute[attribute].name.c_str();
2670
2671 strncpy(name, string, bufsize);
2672 name[bufsize - 1] = '\0';
2673
2674 if (length)
2675 {
2676 *length = strlen(name);
2677 }
2678 }
2679
2680 *size = 1; // Always a single 'type' instance
2681
2682 *type = mLinkedAttribute[attribute].type;
2683}
2684
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002685GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002686{
2687 int count = 0;
2688
2689 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2690 {
2691 if (!mLinkedAttribute[attributeIndex].name.empty())
2692 {
2693 count++;
2694 }
2695 }
2696
2697 return count;
2698}
2699
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002700GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002701{
2702 int maxLength = 0;
2703
2704 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2705 {
2706 if (!mLinkedAttribute[attributeIndex].name.empty())
2707 {
2708 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2709 }
2710 }
2711
2712 return maxLength;
2713}
2714
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002715void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002716{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002717 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002718
2719 if (bufsize > 0)
2720 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002721 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002722
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002723 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002724 {
2725 string += "[0]";
2726 }
2727
2728 strncpy(name, string.c_str(), bufsize);
2729 name[bufsize - 1] = '\0';
2730
2731 if (length)
2732 {
2733 *length = strlen(name);
2734 }
2735 }
2736
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002737 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002738
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002739 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002740}
2741
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002742GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002743{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002744 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002745}
2746
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002747GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002748{
2749 int maxLength = 0;
2750
2751 unsigned int numUniforms = mUniforms.size();
2752 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2753 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002754 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002755 {
2756 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2757 if (mUniforms[uniformIndex]->isArray())
2758 {
2759 length += 3; // Counting in "[0]".
2760 }
2761 maxLength = std::max(length, maxLength);
2762 }
2763 }
2764
2765 return maxLength;
2766}
2767
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002768GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2769{
2770 const gl::Uniform& uniform = *mUniforms[index];
2771
2772 switch (pname)
2773 {
2774 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2775 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002776 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 +00002777 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002778
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002779 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2780 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2781 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2782 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002783
2784 default:
2785 UNREACHABLE();
2786 break;
2787 }
2788 return 0;
2789}
2790
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002791void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2792{
2793 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2794
2795 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2796
2797 if (bufSize > 0)
2798 {
2799 std::string string = uniformBlock.name;
2800
2801 if (uniformBlock.isArrayElement())
2802 {
2803 string += "[" + str(uniformBlock.elementIndex) + "]";
2804 }
2805
2806 strncpy(uniformBlockName, string.c_str(), bufSize);
2807 uniformBlockName[bufSize - 1] = '\0';
2808
2809 if (length)
2810 {
2811 *length = strlen(uniformBlockName);
2812 }
2813 }
2814}
2815
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002816void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2817{
2818 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2819
2820 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2821
2822 switch (pname)
2823 {
2824 case GL_UNIFORM_BLOCK_DATA_SIZE:
2825 *params = static_cast<GLint>(uniformBlock.dataSize);
2826 break;
2827 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002828 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002829 break;
2830 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2831 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2832 break;
2833 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2834 {
2835 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2836 {
2837 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2838 }
2839 }
2840 break;
2841 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2842 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2843 break;
2844 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2845 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2846 break;
2847 default: UNREACHABLE();
2848 }
2849}
2850
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002851GLuint ProgramBinary::getActiveUniformBlockCount() const
2852{
2853 return mUniformBlocks.size();
2854}
2855
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002856GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2857{
2858 unsigned int maxLength = 0;
2859
2860 unsigned int numUniformBlocks = mUniformBlocks.size();
2861 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2862 {
2863 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2864 if (!uniformBlock.name.empty())
2865 {
2866 const unsigned int length = uniformBlock.name.length() + 1;
2867
2868 // Counting in "[0]".
2869 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2870
2871 maxLength = std::max(length + arrayLength, maxLength);
2872 }
2873 }
2874
2875 return maxLength;
2876}
2877
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002878void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002879{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002880 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002881 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002882 {
2883 mValidated = false;
2884 }
2885 else
2886 {
2887 mValidated = true;
2888 }
2889}
2890
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002891bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002892{
2893 // if any two active samplers in a program are of different types, but refer to the same
2894 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2895 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2896
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002897 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002898 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002899
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002900 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002901 {
2902 textureUnitType[i] = TEXTURE_UNKNOWN;
2903 }
2904
2905 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2906 {
2907 if (mSamplersPS[i].active)
2908 {
2909 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2910
2911 if (unit >= maxCombinedTextureImageUnits)
2912 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002913 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002914 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002915 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002916 }
2917
2918 return false;
2919 }
2920
2921 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2922 {
2923 if (mSamplersPS[i].textureType != textureUnitType[unit])
2924 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002925 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002926 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002927 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002928 }
2929
2930 return false;
2931 }
2932 }
2933 else
2934 {
2935 textureUnitType[unit] = mSamplersPS[i].textureType;
2936 }
2937 }
2938 }
2939
2940 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2941 {
2942 if (mSamplersVS[i].active)
2943 {
2944 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2945
2946 if (unit >= maxCombinedTextureImageUnits)
2947 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002948 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002949 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002950 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002951 }
2952
2953 return false;
2954 }
2955
2956 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2957 {
2958 if (mSamplersVS[i].textureType != textureUnitType[unit])
2959 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002960 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002961 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002962 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002963 }
2964
2965 return false;
2966 }
2967 }
2968 else
2969 {
2970 textureUnitType[unit] = mSamplersVS[i].textureType;
2971 }
2972 }
2973 }
2974
2975 return true;
2976}
2977
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002978ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2979{
2980}
2981
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002982struct AttributeSorter
2983{
2984 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2985 : originalIndices(semanticIndices)
2986 {
2987 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2988 {
2989 indices[i] = i;
2990 }
2991
2992 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2993 }
2994
2995 bool operator()(int a, int b)
2996 {
2997 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2998 }
2999
3000 int indices[MAX_VERTEX_ATTRIBS];
3001 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3002};
3003
3004void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3005{
3006 AttributeSorter sorter(mSemanticIndex);
3007
3008 int oldIndices[MAX_VERTEX_ATTRIBS];
3009 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3010
3011 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3012 {
3013 oldIndices[i] = mSemanticIndex[i];
3014 oldTranslatedAttributes[i] = attributes[i];
3015 }
3016
3017 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3018 {
3019 int oldIndex = sorter.indices[i];
3020 sortedSemanticIndices[i] = oldIndices[oldIndex];
3021 attributes[i] = oldTranslatedAttributes[oldIndex];
3022 }
3023}
3024
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003025}