blob: 2a2b11459eca52b749f77ac8ed464a41409131b6 [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.orgb4e07b82013-05-30 00:19:31 +000053 case GL_FLOAT_MAT2: return "float2x2";
54 case GL_FLOAT_MAT3: return "float3x3";
55 case GL_FLOAT_MAT4: return "float4x4";
56 case GL_FLOAT_MAT2x3: return "float2x3";
57 case GL_FLOAT_MAT3x2: return "float3x2";
58 case GL_FLOAT_MAT2x4: return "float2x4";
59 case GL_FLOAT_MAT4x2: return "float4x2";
60 case GL_FLOAT_MAT3x4: return "float3x4";
61 case GL_FLOAT_MAT4x3: return "float4x3";
62 default: UNREACHABLE(); return "invalid-gl-type";
63 }
64 }
65}
66
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000067namespace
68{
69
70unsigned int parseAndStripArrayIndex(std::string* name)
71{
72 unsigned int subscript = GL_INVALID_INDEX;
73
74 // Strip any trailing array operator and retrieve the subscript
75 size_t open = name->find_last_of('[');
76 size_t close = name->find_last_of(']');
77 if (open != std::string::npos && close == name->length() - 1)
78 {
79 subscript = atoi(name->substr(open + 1).c_str());
80 name->erase(open);
81 }
82
83 return subscript;
84}
85
86}
87
daniel@transgaming.comdb019952012-12-20 21:13:32 +000088UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
89 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000090{
91}
92
daniel@transgaming.come87ca002012-07-24 18:30:43 +000093unsigned int ProgramBinary::mCurrentSerial = 1;
94
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000095ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000096{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097 mPixelExecutable = NULL;
98 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000099 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000100
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101 mValidated = false;
102
103 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
104 {
105 mSemanticIndex[index] = -1;
106 }
107
108 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
109 {
110 mSamplersPS[index].active = false;
111 }
112
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000113 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000114 {
115 mSamplersVS[index].active = false;
116 }
117
118 mUsedVertexSamplerRange = 0;
119 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000120 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000121 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000122}
123
124ProgramBinary::~ProgramBinary()
125{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000126 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000127 mPixelExecutable = NULL;
128
daniel@transgaming.com95892412012-11-28 20:59:09 +0000129 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000130 mVertexExecutable = NULL;
131
132 delete mGeometryExecutable;
133 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000134
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135 while (!mUniforms.empty())
136 {
137 delete mUniforms.back();
138 mUniforms.pop_back();
139 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000140
141 while (!mUniformBlocks.empty())
142 {
143 delete mUniformBlocks.back();
144 mUniformBlocks.pop_back();
145 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000146}
147
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000148unsigned int ProgramBinary::getSerial() const
149{
150 return mSerial;
151}
152
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000153int ProgramBinary::getShaderVersion() const
154{
155 return mShaderVersion;
156}
157
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000158unsigned int ProgramBinary::issueSerial()
159{
160 return mCurrentSerial++;
161}
162
daniel@transgaming.com95892412012-11-28 20:59:09 +0000163rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000164{
165 return mPixelExecutable;
166}
167
daniel@transgaming.com95892412012-11-28 20:59:09 +0000168rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000169{
170 return mVertexExecutable;
171}
172
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000173rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
174{
175 return mGeometryExecutable;
176}
177
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000178GLuint ProgramBinary::getAttributeLocation(const char *name)
179{
180 if (name)
181 {
182 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
183 {
184 if (mLinkedAttribute[index].name == std::string(name))
185 {
186 return index;
187 }
188 }
189 }
190
191 return -1;
192}
193
194int ProgramBinary::getSemanticIndex(int attributeIndex)
195{
196 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
197
198 return mSemanticIndex[attributeIndex];
199}
200
201// Returns one more than the highest sampler index used.
202GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
203{
204 switch (type)
205 {
206 case SAMPLER_PIXEL:
207 return mUsedPixelSamplerRange;
208 case SAMPLER_VERTEX:
209 return mUsedVertexSamplerRange;
210 default:
211 UNREACHABLE();
212 return 0;
213 }
214}
215
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000216bool ProgramBinary::usesPointSize() const
217{
218 return mUsesPointSize;
219}
220
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000221bool ProgramBinary::usesPointSpriteEmulation() const
222{
223 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
224}
225
226bool ProgramBinary::usesGeometryShader() const
227{
228 return usesPointSpriteEmulation();
229}
230
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000231// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
232// index (0-15 for the pixel shader and 0-3 for the vertex shader).
233GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
234{
235 GLint logicalTextureUnit = -1;
236
237 switch (type)
238 {
239 case SAMPLER_PIXEL:
240 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
241
242 if (mSamplersPS[samplerIndex].active)
243 {
244 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
245 }
246 break;
247 case SAMPLER_VERTEX:
248 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
249
250 if (mSamplersVS[samplerIndex].active)
251 {
252 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
253 }
254 break;
255 default: UNREACHABLE();
256 }
257
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000258 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000259 {
260 return logicalTextureUnit;
261 }
262
263 return -1;
264}
265
266// Returns the texture type for a given Direct3D 9 sampler type and
267// index (0-15 for the pixel shader and 0-3 for the vertex shader).
268TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
269{
270 switch (type)
271 {
272 case SAMPLER_PIXEL:
273 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
274 ASSERT(mSamplersPS[samplerIndex].active);
275 return mSamplersPS[samplerIndex].textureType;
276 case SAMPLER_VERTEX:
277 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
278 ASSERT(mSamplersVS[samplerIndex].active);
279 return mSamplersVS[samplerIndex].textureType;
280 default: UNREACHABLE();
281 }
282
283 return TEXTURE_2D;
284}
285
286GLint ProgramBinary::getUniformLocation(std::string name)
287{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000288 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000289
290 unsigned int numUniforms = mUniformIndex.size();
291 for (unsigned int location = 0; location < numUniforms; location++)
292 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000293 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000294 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000295 const int index = mUniformIndex[location].index;
296 const bool isArray = mUniforms[index]->isArray();
297
298 if ((isArray && mUniformIndex[location].element == subscript) ||
299 (subscript == GL_INVALID_INDEX))
300 {
301 return location;
302 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000303 }
304 }
305
306 return -1;
307}
308
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000309GLuint ProgramBinary::getUniformIndex(std::string name)
310{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000311 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000312
313 // The app is not allowed to specify array indices other than 0 for arrays of basic types
314 if (subscript != 0 && subscript != GL_INVALID_INDEX)
315 {
316 return GL_INVALID_INDEX;
317 }
318
319 unsigned int numUniforms = mUniforms.size();
320 for (unsigned int index = 0; index < numUniforms; index++)
321 {
322 if (mUniforms[index]->name == name)
323 {
324 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
325 {
326 return index;
327 }
328 }
329 }
330
331 return GL_INVALID_INDEX;
332}
333
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000334GLuint ProgramBinary::getUniformBlockIndex(std::string name)
335{
336 unsigned int subscript = parseAndStripArrayIndex(&name);
337
338 unsigned int numUniformBlocks = mUniformBlocks.size();
339 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
340 {
341 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
342 if (uniformBlock.name == name)
343 {
344 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
345 if (subscript == uniformBlock.elementIndex || arrayElementZero)
346 {
347 return blockIndex;
348 }
349 }
350 }
351
352 return GL_INVALID_INDEX;
353}
354
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000355UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
356{
357 ASSERT(blockIndex < mUniformBlocks.size());
358 return mUniformBlocks[blockIndex];
359}
360
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000361template <typename T>
362bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000363{
364 if (location < 0 || location >= (int)mUniformIndex.size())
365 {
366 return false;
367 }
368
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000369 const int components = UniformComponentCount(targetUniformType);
370 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
371
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
373 targetUniform->dirty = true;
374
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000375 int elementCount = targetUniform->elementCount();
376
377 if (elementCount == 1 && count > 1)
378 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
379
380 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
381
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000382 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000383 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000384 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000385
386 for (int i = 0; i < count; i++)
387 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000388 for (int c = 0; c < components; c++)
389 {
390 target[c] = v[c];
391 }
392 for (int c = components; c < 4; c++)
393 {
394 target[c] = 0;
395 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000396 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000397 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398 }
399 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000400 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000401 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000402 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000403
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000404 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000406 for (int c = 0; c < components; c++)
407 {
408 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
409 }
410 for (int c = components; c < 4; c++)
411 {
412 boolParams[c] = GL_FALSE;
413 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000414 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000415 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000416 }
417 }
418 else
419 {
420 return false;
421 }
422
423 return true;
424}
425
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000426bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
427{
428 return setUniform(location, count, v, GL_FLOAT);
429}
430
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000431bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
432{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000433 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000434}
435
436bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
437{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000438 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439}
440
441bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
442{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000443 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000444}
445
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000446template<typename T>
447void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000449 int copyWidth = std::min(targetHeight, srcWidth);
450 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000451
452 for (int x = 0; x < copyWidth; x++)
453 {
454 for (int y = 0; y < copyHeight; y++)
455 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000456 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000457 }
458 }
459 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000460 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000461 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000462 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000463 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000464 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465 }
466 }
467 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000468 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000469 {
470 for (int x = 0; x < targetWidth; x++)
471 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000472 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000473 }
474 }
475}
476
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000477template<typename T>
478void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
479{
480 int copyWidth = std::min(targetWidth, srcWidth);
481 int copyHeight = std::min(targetHeight, srcHeight);
482
483 for (int y = 0; y < copyHeight; y++)
484 {
485 for (int x = 0; x < copyWidth; x++)
486 {
487 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
488 }
489 }
490 // clear unfilled right side
491 for (int y = 0; y < copyHeight; y++)
492 {
493 for (int x = copyWidth; x < targetWidth; x++)
494 {
495 target[y * targetWidth + x] = static_cast<T>(0);
496 }
497 }
498 // clear unfilled bottom.
499 for (int y = copyHeight; y < targetHeight; y++)
500 {
501 for (int x = 0; x < targetWidth; x++)
502 {
503 target[y * targetWidth + x] = static_cast<T>(0);
504 }
505 }
506}
507
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000508template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000509bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000510{
511 if (location < 0 || location >= (int)mUniformIndex.size())
512 {
513 return false;
514 }
515
516 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
517 targetUniform->dirty = true;
518
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000519 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000520 {
521 return false;
522 }
523
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000524 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000525
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000526 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000527 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
528
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000529 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000530 const unsigned int targetMatrixStride = (4 * rows);
531 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000532
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000533 for (int i = 0; i < count; i++)
534 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000535 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
536 if (transpose == GL_FALSE)
537 {
538 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
539 }
540 else
541 {
542 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
543 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000544 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000545 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000546 }
547
548 return true;
549}
550
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000551bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000552{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000553 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000554}
555
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000556bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000557{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000558 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559}
560
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000561bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000563 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000564}
565
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000566bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000567{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000568 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000569}
570
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000571bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000572{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000573 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000574}
575
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000576bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000577{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000578 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000579}
580
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000581bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000582{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000583 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000584}
585
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000586bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000587{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000588 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000589}
590
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000591bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000592{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000593 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000594}
595
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000596bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
597{
598 if (location < 0 || location >= (int)mUniformIndex.size())
599 {
600 return false;
601 }
602
603 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
604 targetUniform->dirty = true;
605
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000606 int elementCount = targetUniform->elementCount();
607
608 if (elementCount == 1 && count > 1)
609 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
610
611 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
612
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613 if (targetUniform->type == GL_INT ||
614 targetUniform->type == GL_SAMPLER_2D ||
615 targetUniform->type == GL_SAMPLER_CUBE)
616 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000617 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000618
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000619 for (int i = 0; i < count; i++)
620 {
621 target[0] = v[0];
622 target[1] = 0;
623 target[2] = 0;
624 target[3] = 0;
625 target += 4;
626 v += 1;
627 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628 }
629 else if (targetUniform->type == GL_BOOL)
630 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000631 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000632
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000633 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000634 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000635 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
636 boolParams[1] = GL_FALSE;
637 boolParams[2] = GL_FALSE;
638 boolParams[3] = GL_FALSE;
639 boolParams += 4;
640 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000641 }
642 }
643 else
644 {
645 return false;
646 }
647
648 return true;
649}
650
651bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
652{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000653 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654}
655
656bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
657{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000658 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000659}
660
661bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
662{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000663 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000664}
665
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000666bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
667{
668 return setUniform(location, count, v, GL_UNSIGNED_INT);
669}
670
671bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
672{
673 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
674}
675
676bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
677{
678 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
679}
680
681bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
682{
683 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
684}
685
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000686template <typename T>
687bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000688{
689 if (location < 0 || location >= (int)mUniformIndex.size())
690 {
691 return false;
692 }
693
694 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
695
696 // sized queries -- ensure the provided buffer is large enough
697 if (bufSize)
698 {
699 int requiredBytes = UniformExternalSize(targetUniform->type);
700 if (*bufSize < requiredBytes)
701 {
702 return false;
703 }
704 }
705
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000706 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000707 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000708 const int rows = VariableRowCount(targetUniform->type);
709 const int cols = VariableColumnCount(targetUniform->type);
710 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
711 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000712 else if (uniformType == UniformComponentType(targetUniform->type))
713 {
714 unsigned int size = UniformComponentCount(targetUniform->type);
715 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
716 size * sizeof(T));
717 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000718 else
719 {
720 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000721 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000722 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000723 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000724 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000725 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000727 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000728 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000729 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000730 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000731 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000732 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000733
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000734 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000735 {
736 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
737
738 for (unsigned int i = 0; i < size; i++)
739 {
740 params[i] = static_cast<T>(floatParams[i]);
741 }
742 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000743 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000744
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000745 case GL_INT:
746 {
747 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
748
749 for (unsigned int i = 0; i < size; i++)
750 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000751 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000752 }
753 }
754 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000755
756 case GL_UNSIGNED_INT:
757 {
758 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000759
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000760 for (unsigned int i = 0; i < size; i++)
761 {
762 params[i] = static_cast<T>(uintParams[i]);
763 }
764 }
765 break;
766
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000767 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000768 }
769 }
770
771 return true;
772}
773
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000774bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
775{
776 return getUniformv(location, bufSize, params, GL_FLOAT);
777}
778
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000779bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
780{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000781 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000782}
783
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000784bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
785{
786 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
787}
788
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789void ProgramBinary::dirtyAllUniforms()
790{
791 unsigned int numUniforms = mUniforms.size();
792 for (unsigned int index = 0; index < numUniforms; index++)
793 {
794 mUniforms[index]->dirty = true;
795 }
796}
797
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000798// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000799void ProgramBinary::applyUniforms()
800{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000801 // Retrieve sampler uniform values
802 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
803 {
804 Uniform *targetUniform = *ub;
805
806 if (targetUniform->dirty)
807 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000808 if (targetUniform->type == GL_SAMPLER_2D ||
809 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000810 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000811 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000812 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000813
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000814 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000815 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000816 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000817
818 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000819 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000820 unsigned int samplerIndex = firstIndex + i;
821
822 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000823 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000824 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000825 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000826 }
827 }
828 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000829
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000830 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000831 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000832 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000833
834 for (int i = 0; i < count; i++)
835 {
836 unsigned int samplerIndex = firstIndex + i;
837
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000838 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000839 {
840 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000841 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000842 }
843 }
844 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000845 }
846 }
847 }
848
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000849 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000850}
851
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000852bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
853{
854 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
855 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
856
857 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
858 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
859
860 ASSERT(boundBuffers.size() == mUniformBlocks.size());
861
862 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
863 {
864 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
865 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
866
867 ASSERT(uniformBlock && uniformBuffer);
868
869 if (uniformBuffer->size() < uniformBlock->dataSize)
870 {
871 // undefined behaviour
872 return false;
873 }
874
875 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
876
877 if (uniformBlock->isReferencedByVertexShader())
878 {
879 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
880 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
881 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
882 vertexUniformBuffers[registerIndex] = uniformBuffer;
883 }
884
885 if (uniformBlock->isReferencedByFragmentShader())
886 {
887 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
888 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
889 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
890 fragmentUniformBuffers[registerIndex] = uniformBuffer;
891 }
892 }
893
894 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
895}
896
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000897// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
898// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000899int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000900{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000901 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000902
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000903 fragmentShader->resetVaryingsRegisterAssignment();
904
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000905 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
906 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000907 GLenum transposedType = TransposeMatrixType(varying->type);
908 int n = VariableRowCount(transposedType) * varying->size;
909 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000910 bool success = false;
911
912 if (m == 2 || m == 3 || m == 4)
913 {
914 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
915 {
916 bool available = true;
917
918 for (int y = 0; y < n && available; y++)
919 {
920 for (int x = 0; x < m && available; x++)
921 {
922 if (packing[r + y][x])
923 {
924 available = false;
925 }
926 }
927 }
928
929 if (available)
930 {
931 varying->reg = r;
932 varying->col = 0;
933
934 for (int y = 0; y < n; y++)
935 {
936 for (int x = 0; x < m; x++)
937 {
938 packing[r + y][x] = &*varying;
939 }
940 }
941
942 success = true;
943 }
944 }
945
946 if (!success && m == 2)
947 {
948 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
949 {
950 bool available = true;
951
952 for (int y = 0; y < n && available; y++)
953 {
954 for (int x = 2; x < 4 && available; x++)
955 {
956 if (packing[r + y][x])
957 {
958 available = false;
959 }
960 }
961 }
962
963 if (available)
964 {
965 varying->reg = r;
966 varying->col = 2;
967
968 for (int y = 0; y < n; y++)
969 {
970 for (int x = 2; x < 4; x++)
971 {
972 packing[r + y][x] = &*varying;
973 }
974 }
975
976 success = true;
977 }
978 }
979 }
980 }
981 else if (m == 1)
982 {
983 int space[4] = {0};
984
985 for (int y = 0; y < maxVaryingVectors; y++)
986 {
987 for (int x = 0; x < 4; x++)
988 {
989 space[x] += packing[y][x] ? 0 : 1;
990 }
991 }
992
993 int column = 0;
994
995 for (int x = 0; x < 4; x++)
996 {
997 if (space[x] >= n && space[x] < space[column])
998 {
999 column = x;
1000 }
1001 }
1002
1003 if (space[column] >= n)
1004 {
1005 for (int r = 0; r < maxVaryingVectors; r++)
1006 {
1007 if (!packing[r][column])
1008 {
1009 varying->reg = r;
1010
1011 for (int y = r; y < r + n; y++)
1012 {
1013 packing[y][column] = &*varying;
1014 }
1015
1016 break;
1017 }
1018 }
1019
1020 varying->col = column;
1021
1022 success = true;
1023 }
1024 }
1025 else UNREACHABLE();
1026
1027 if (!success)
1028 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001029 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001030
1031 return -1;
1032 }
1033 }
1034
1035 // Return the number of used registers
1036 int registers = 0;
1037
1038 for (int r = 0; r < maxVaryingVectors; r++)
1039 {
1040 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1041 {
1042 registers++;
1043 }
1044 }
1045
1046 return registers;
1047}
1048
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001049bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1050 std::string& pixelHLSL, std::string& vertexHLSL,
1051 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052{
1053 if (pixelHLSL.empty() || vertexHLSL.empty())
1054 {
1055 return false;
1056 }
1057
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001058 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1059 bool usesFragColor = fragmentShader->mUsesFragColor;
1060 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001061 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001062 {
1063 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1064 return false;
1065 }
1066
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001067 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001068 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001069 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001070
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001071 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1072
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001073 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1074 // - with a 3.0 context, the output color is copied to channel 0
1075 // - with a 2.0 context, the output color is broadcast to all channels
1076 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1077 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1078
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001079 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001080 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001081 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001082
1083 return false;
1084 }
1085
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001086 vertexShader->resetVaryingsRegisterAssignment();
1087
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001088 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1089 {
1090 bool matched = false;
1091
1092 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1093 {
1094 if (output->name == input->name)
1095 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001096 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001097 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001098 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 +00001099
1100 return false;
1101 }
1102
1103 output->reg = input->reg;
1104 output->col = input->col;
1105
1106 matched = true;
1107 break;
1108 }
1109 }
1110
1111 if (!matched)
1112 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001113 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001114
1115 return false;
1116 }
1117 }
1118
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001119 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001120 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001121 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001122 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1123
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001124 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1125
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001126 // special varyings that use reserved registers
1127 int reservedRegisterIndex = registers;
1128 std::string fragCoordSemantic;
1129 std::string pointCoordSemantic;
1130
1131 if (fragmentShader->mUsesFragCoord)
1132 {
1133 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1134 }
1135
1136 if (fragmentShader->mUsesPointCoord)
1137 {
1138 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1139 // In DX11 we compute this in the GS.
1140 if (shaderModel == 3)
1141 {
1142 pointCoordSemantic = "TEXCOORD0";
1143 }
1144 else if (shaderModel >= 4)
1145 {
1146 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1147 }
1148 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001149
1150 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001151 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001152
1153 int semanticIndex = 0;
1154 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1155 {
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001156 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute->type)) + " ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001157 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1158
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001159 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001160 }
1161
1162 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001163 "\n"
1164 "struct VS_OUTPUT\n"
1165 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001166
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001167 if (shaderModel < 4)
1168 {
1169 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1170 }
1171
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001172 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001173
1174 if (fragmentShader->mUsesFragCoord)
1175 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001176 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001177 }
1178
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001179 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001180 {
1181 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1182 }
1183
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001184 if (shaderModel >= 4)
1185 {
1186 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1187 }
1188
1189 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001190 "\n"
1191 "VS_OUTPUT main(VS_INPUT input)\n"
1192 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001193
1194 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1195 {
1196 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1197
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001198 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001199 {
1200 vertexHLSL += "transpose";
1201 }
1202
1203 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1204 }
1205
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001206 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1207 {
1208 vertexHLSL += "\n"
1209 " dx_initConstantBuffers();\n";
1210 }
1211
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001212 if (shaderModel >= 4)
1213 {
1214 vertexHLSL += "\n"
1215 " gl_main();\n"
1216 "\n"
1217 " VS_OUTPUT output;\n"
1218 " output.gl_Position.x = gl_Position.x;\n"
1219 " output.gl_Position.y = -gl_Position.y;\n"
1220 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1221 " output.gl_Position.w = gl_Position.w;\n";
1222 }
1223 else
1224 {
1225 vertexHLSL += "\n"
1226 " gl_main();\n"
1227 "\n"
1228 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001229 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1230 " 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 +00001231 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1232 " output.gl_Position.w = gl_Position.w;\n";
1233 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001235 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001236 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001237 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001238 }
1239
1240 if (fragmentShader->mUsesFragCoord)
1241 {
1242 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1243 }
1244
1245 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1246 {
1247 if (varying->reg >= 0)
1248 {
1249 for (int i = 0; i < varying->size; i++)
1250 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001251 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001252
1253 for (int j = 0; j < rows; j++)
1254 {
1255 int r = varying->reg + i * rows + j;
1256 vertexHLSL += " output.v" + str(r);
1257
1258 bool sharedRegister = false; // Register used by multiple varyings
1259
1260 for (int x = 0; x < 4; x++)
1261 {
1262 if (packing[r][x] && packing[r][x] != packing[r][0])
1263 {
1264 sharedRegister = true;
1265 break;
1266 }
1267 }
1268
1269 if(sharedRegister)
1270 {
1271 vertexHLSL += ".";
1272
1273 for (int x = 0; x < 4; x++)
1274 {
1275 if (packing[r][x] == &*varying)
1276 {
1277 switch(x)
1278 {
1279 case 0: vertexHLSL += "x"; break;
1280 case 1: vertexHLSL += "y"; break;
1281 case 2: vertexHLSL += "z"; break;
1282 case 3: vertexHLSL += "w"; break;
1283 }
1284 }
1285 }
1286 }
1287
1288 vertexHLSL += " = " + varying->name;
1289
1290 if (varying->array)
1291 {
1292 vertexHLSL += "[" + str(i) + "]";
1293 }
1294
1295 if (rows > 1)
1296 {
1297 vertexHLSL += "[" + str(j) + "]";
1298 }
1299
1300 vertexHLSL += ";\n";
1301 }
1302 }
1303 }
1304 }
1305
1306 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001307 " return output;\n"
1308 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001309
1310 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001311 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001312
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001313 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314
1315 if (fragmentShader->mUsesFragCoord)
1316 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001317 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001318 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001319
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001320 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1321 {
1322 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1323 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001324
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001325 // Must consume the PSIZE element if the geometry shader is not active
1326 // We won't know if we use a GS until we draw
1327 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1328 {
1329 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1330 }
1331
1332 if (fragmentShader->mUsesFragCoord)
1333 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001334 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001335 {
1336 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1337 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001338 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001339 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001340 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1341 }
1342 }
1343
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001344 pixelHLSL += "};\n"
1345 "\n"
1346 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001347 "{\n";
1348
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001349 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001350 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001351 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001352 }
1353
1354 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001355 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001356
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001357 if (fragmentShader->mUsesFrontFacing)
1358 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001359 if (shaderModel >= 4)
1360 {
1361 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1362 "{\n";
1363 }
1364 else
1365 {
1366 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1367 "{\n";
1368 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001369 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001370 else
1371 {
1372 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1373 "{\n";
1374 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001375
1376 if (fragmentShader->mUsesFragCoord)
1377 {
1378 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1379
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001380 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001381 {
1382 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1383 " gl_FragCoord.y = input.dx_VPos.y;\n";
1384 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001385 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001386 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001387 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001388 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001389 }
1390 else
1391 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001392 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1393 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1394 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001395 }
1396
daniel@transgaming.com12985182012-12-20 20:56:31 +00001397 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001398 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001399 }
1400
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001401 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001402 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001403 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1404 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001405 }
1406
1407 if (fragmentShader->mUsesFrontFacing)
1408 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001409 if (shaderModel <= 3)
1410 {
1411 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1412 }
1413 else
1414 {
1415 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1416 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001417 }
1418
1419 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1420 {
1421 if (varying->reg >= 0)
1422 {
1423 for (int i = 0; i < varying->size; i++)
1424 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001425 GLenum transposedType = TransposeMatrixType(varying->type);
1426 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001427 for (int j = 0; j < rows; j++)
1428 {
1429 std::string n = str(varying->reg + i * rows + j);
1430 pixelHLSL += " " + varying->name;
1431
1432 if (varying->array)
1433 {
1434 pixelHLSL += "[" + str(i) + "]";
1435 }
1436
1437 if (rows > 1)
1438 {
1439 pixelHLSL += "[" + str(j) + "]";
1440 }
1441
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001442 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001443 {
1444 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1445 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1446 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1447 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1448 default: UNREACHABLE();
1449 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001450 }
1451 }
1452 }
1453 else UNREACHABLE();
1454 }
1455
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001456 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1457 {
1458 pixelHLSL += "\n"
1459 " dx_initConstantBuffers();\n";
1460 }
1461
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001462 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001463 " gl_main();\n"
1464 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001465 " PS_OUTPUT output;\n";
1466
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001467 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001468 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001469 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001470
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001471 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001472 }
1473
1474 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001475 " return output;\n"
1476 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001477
1478 return true;
1479}
1480
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001481std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1482{
1483 std::string varyingHLSL;
1484
1485 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1486 {
1487 if (varying->reg >= 0)
1488 {
1489 for (int i = 0; i < varying->size; i++)
1490 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001491 GLenum transposedType = TransposeMatrixType(varying->type);
1492 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001493 for (int j = 0; j < rows; j++)
1494 {
1495 switch (varying->interpolation)
1496 {
1497 case Smooth: varyingHLSL += " "; break;
1498 case Flat: varyingHLSL += " nointerpolation "; break;
1499 case Centroid: varyingHLSL += " centroid "; break;
1500 default: UNREACHABLE();
1501 }
1502
1503 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001504 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001505
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001506 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001507 }
1508 }
1509 }
1510 else UNREACHABLE();
1511 }
1512
1513 return varyingHLSL;
1514}
1515
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001516bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1517{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001518 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001519
1520 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001521 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001522 if (format != GL_PROGRAM_BINARY_ANGLE)
1523 {
1524 infoLog.append("Invalid program binary format.");
1525 return false;
1526 }
1527
1528 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001529 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001530 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001531 {
1532 infoLog.append("Invalid program binary version.");
1533 return false;
1534 }
1535
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001536 int compileFlags = 0;
1537 stream.read(&compileFlags);
1538 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1539 {
1540 infoLog.append("Mismatched compilation flags.");
1541 return false;
1542 }
1543
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001544 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1545 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001546 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001547 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001548 stream.read(&name);
1549 mLinkedAttribute[i].name = name;
1550 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 }
1552
1553 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1554 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001555 stream.read(&mSamplersPS[i].active);
1556 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001557
1558 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001559 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001560 mSamplersPS[i].textureType = (TextureType) textureType;
1561 }
1562
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001563 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001564 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001565 stream.read(&mSamplersVS[i].active);
1566 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001567
1568 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001569 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001570 mSamplersVS[i].textureType = (TextureType) textureType;
1571 }
1572
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001573 stream.read(&mUsedVertexSamplerRange);
1574 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001575 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001576 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001577
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001578 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001579 stream.read(&size);
1580 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001581 {
1582 infoLog.append("Invalid program binary.");
1583 return false;
1584 }
1585
1586 mUniforms.resize(size);
1587 for (unsigned int i = 0; i < size; ++i)
1588 {
1589 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001590 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001591 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001593 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001594
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001595 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001596 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001597 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001598 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001599 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001601 int offset;
1602 int arrayStride;
1603 int matrixStride;
1604 bool isRowMajorMatrix;
1605
1606 stream.read(&offset);
1607 stream.read(&arrayStride);
1608 stream.read(&matrixStride);
1609 stream.read(&isRowMajorMatrix);
1610
1611 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1612
1613 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001615 stream.read(&mUniforms[i]->psRegisterIndex);
1616 stream.read(&mUniforms[i]->vsRegisterIndex);
1617 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618 }
1619
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001620 stream.read(&size);
1621 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001622 {
1623 infoLog.append("Invalid program binary.");
1624 return false;
1625 }
1626
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001627 mUniformBlocks.resize(size);
1628 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1629 {
1630 std::string name;
1631 unsigned int elementIndex;
1632 unsigned int dataSize;
1633
1634 stream.read(&name);
1635 stream.read(&elementIndex);
1636 stream.read(&dataSize);
1637
1638 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1639
1640 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1641 stream.read(&uniformBlock.psRegisterIndex);
1642 stream.read(&uniformBlock.vsRegisterIndex);
1643
1644 size_t numMembers;
1645 stream.read(&numMembers);
1646 uniformBlock.memberUniformIndexes.resize(numMembers);
1647 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1648 {
1649 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1650 }
1651 }
1652
1653 stream.read(&size);
1654 if (stream.error())
1655 {
1656 infoLog.append("Invalid program binary.");
1657 return false;
1658 }
1659
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 mUniformIndex.resize(size);
1661 for (unsigned int i = 0; i < size; ++i)
1662 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&mUniformIndex[i].name);
1664 stream.read(&mUniformIndex[i].element);
1665 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666 }
1667
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001670
1671 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001674 unsigned int geometryShaderSize;
1675 stream.read(&geometryShaderSize);
1676
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001677 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001678
daniel@transgaming.com36038542012-11-28 20:59:26 +00001679 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001680 ptr += sizeof(GUID);
1681
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001682 GUID identifier = mRenderer->getAdapterIdentifier();
1683 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684 {
1685 infoLog.append("Invalid program binary.");
1686 return false;
1687 }
1688
1689 const char *pixelShaderFunction = ptr;
1690 ptr += pixelShaderSize;
1691
1692 const char *vertexShaderFunction = ptr;
1693 ptr += vertexShaderSize;
1694
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001695 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1696 ptr += geometryShaderSize;
1697
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001698 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001699 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001700 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001701 {
1702 infoLog.append("Could not create pixel shader.");
1703 return false;
1704 }
1705
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001706 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001707 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001708 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001709 {
1710 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001711 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712 mPixelExecutable = NULL;
1713 return false;
1714 }
1715
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001716 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1717 {
1718 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1719 geometryShaderSize, rx::SHADER_GEOMETRY);
1720 if (!mGeometryExecutable)
1721 {
1722 infoLog.append("Could not create geometry shader.");
1723 delete mPixelExecutable;
1724 mPixelExecutable = NULL;
1725 delete mVertexExecutable;
1726 mVertexExecutable = NULL;
1727 return false;
1728 }
1729 }
1730 else
1731 {
1732 mGeometryExecutable = NULL;
1733 }
1734
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735 return true;
1736}
1737
1738bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1739{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001740 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001743 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001744 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745
1746 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1747 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001748 stream.write(mLinkedAttribute[i].type);
1749 stream.write(mLinkedAttribute[i].name);
1750 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 }
1752
1753 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1754 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001755 stream.write(mSamplersPS[i].active);
1756 stream.write(mSamplersPS[i].logicalTextureUnit);
1757 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758 }
1759
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001760 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001761 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001762 stream.write(mSamplersVS[i].active);
1763 stream.write(mSamplersVS[i].logicalTextureUnit);
1764 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 }
1766
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.write(mUsedVertexSamplerRange);
1768 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001769 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001770 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001772 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001773 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001775 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001777 stream.write(uniform.type);
1778 stream.write(uniform.precision);
1779 stream.write(uniform.name);
1780 stream.write(uniform.arraySize);
1781 stream.write(uniform.blockIndex);
1782
1783 stream.write(uniform.blockInfo.offset);
1784 stream.write(uniform.blockInfo.arrayStride);
1785 stream.write(uniform.blockInfo.matrixStride);
1786 stream.write(uniform.blockInfo.isRowMajorMatrix);
1787
1788 stream.write(uniform.psRegisterIndex);
1789 stream.write(uniform.vsRegisterIndex);
1790 stream.write(uniform.registerCount);
1791 }
1792
1793 stream.write(mUniformBlocks.size());
1794 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1795 {
1796 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1797
1798 stream.write(uniformBlock.name);
1799 stream.write(uniformBlock.elementIndex);
1800 stream.write(uniformBlock.dataSize);
1801
1802 stream.write(uniformBlock.memberUniformIndexes.size());
1803 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1804 {
1805 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1806 }
1807
1808 stream.write(uniformBlock.psRegisterIndex);
1809 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001810 }
1811
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001812 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1814 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001815 stream.write(mUniformIndex[i].name);
1816 stream.write(mUniformIndex[i].element);
1817 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001818 }
1819
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001820 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001821 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001823 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001824 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001826 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1827 stream.write(geometryShaderSize);
1828
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001829 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001830
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001831 GLsizei streamLength = stream.length();
1832 const void *streamData = stream.data();
1833
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001834 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001835 if (totalLength > bufSize)
1836 {
1837 if (length)
1838 {
1839 *length = 0;
1840 }
1841
1842 return false;
1843 }
1844
1845 if (binary)
1846 {
1847 char *ptr = (char*) binary;
1848
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001849 memcpy(ptr, streamData, streamLength);
1850 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001851
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001852 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001853 ptr += sizeof(GUID);
1854
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001855 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001856 ptr += pixelShaderSize;
1857
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001858 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001859 ptr += vertexShaderSize;
1860
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001861 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1862 {
1863 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1864 ptr += geometryShaderSize;
1865 }
1866
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001867 ASSERT(ptr - totalLength == binary);
1868 }
1869
1870 if (length)
1871 {
1872 *length = totalLength;
1873 }
1874
1875 return true;
1876}
1877
1878GLint ProgramBinary::getLength()
1879{
1880 GLint length;
1881 if (save(NULL, INT_MAX, &length))
1882 {
1883 return length;
1884 }
1885 else
1886 {
1887 return 0;
1888 }
1889}
1890
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001891bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001892{
1893 if (!fragmentShader || !fragmentShader->isCompiled())
1894 {
1895 return false;
1896 }
1897
1898 if (!vertexShader || !vertexShader->isCompiled())
1899 {
1900 return false;
1901 }
1902
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001903 mShaderVersion = vertexShader->getShaderVersion();
1904
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001905 std::string pixelHLSL = fragmentShader->getHLSL();
1906 std::string vertexHLSL = vertexShader->getHLSL();
1907
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001908 // Map the varyings to the register file
1909 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1910 int registers = packVaryings(infoLog, packing, fragmentShader);
1911
1912 if (registers < 0)
1913 {
1914 return false;
1915 }
1916
1917 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001918 {
1919 return false;
1920 }
1921
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001922 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001923 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1924 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001925
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001926 if (usesGeometryShader())
1927 {
1928 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1929 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1930 }
1931
1932 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001933 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001934 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001935 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001936
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001937 delete mVertexExecutable;
1938 mVertexExecutable = NULL;
1939 delete mPixelExecutable;
1940 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001941 delete mGeometryExecutable;
1942 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001943 }
1944
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001945 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1946 {
1947 success = false;
1948 }
1949
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001950 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001951 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001952 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001953 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001954
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001955 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1956 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1957 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001958 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1959 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1960 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 +00001961 }
1962
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001963 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1964 {
1965 success = false;
1966 }
1967
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001968 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001969}
1970
1971// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001972bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001973{
1974 unsigned int usedLocations = 0;
1975
1976 // Link attributes that have a binding location
1977 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1978 {
1979 int location = attributeBindings.getAttributeBinding(attribute->name);
1980
1981 if (location != -1) // Set by glBindAttribLocation
1982 {
1983 if (!mLinkedAttribute[location].name.empty())
1984 {
1985 // Multiple active attributes bound to the same location; not an error
1986 }
1987
1988 mLinkedAttribute[location] = *attribute;
1989
1990 int rows = VariableRowCount(attribute->type);
1991
1992 if (rows + location > MAX_VERTEX_ATTRIBS)
1993 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001994 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 +00001995
1996 return false;
1997 }
1998
1999 for (int i = 0; i < rows; i++)
2000 {
2001 usedLocations |= 1 << (location + i);
2002 }
2003 }
2004 }
2005
2006 // Link attributes that don't have a binding location
2007 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2008 {
2009 int location = attributeBindings.getAttributeBinding(attribute->name);
2010
2011 if (location == -1) // Not set by glBindAttribLocation
2012 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002013 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002014 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2015
2016 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2017 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002018 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002019
2020 return false; // Fail to link
2021 }
2022
2023 mLinkedAttribute[availableIndex] = *attribute;
2024 }
2025 }
2026
2027 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2028 {
2029 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002030 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002031
2032 for (int r = 0; r < rows; r++)
2033 {
2034 mSemanticIndex[attributeIndex++] = index++;
2035 }
2036 }
2037
2038 return true;
2039}
2040
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002041bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2042{
2043 if (vertexUniform.type != fragmentUniform.type)
2044 {
2045 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2046 return false;
2047 }
2048 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2049 {
2050 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2051 return false;
2052 }
2053 else if (vertexUniform.precision != fragmentUniform.precision)
2054 {
2055 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2056 return false;
2057 }
2058 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2059 {
2060 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2061 }
2062
2063 const unsigned int numMembers = vertexUniform.fields.size();
2064 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2065 {
2066 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2067 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2068
2069 if (vertexMember.name != fragmentMember.name)
2070 {
2071 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2072 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2073 return false;
2074 }
2075
2076 const std::string memberName = uniformName + "." + vertexUniform.name;
2077 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2078 {
2079 return false;
2080 }
2081 }
2082
2083 return true;
2084}
2085
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002086bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002087{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002088 // Check that uniforms defined in the vertex and fragment shaders are identical
2089 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2090 UniformMap linkedUniforms;
2091
2092 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2093 {
2094 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2095 linkedUniforms[vertexUniform.name] = &vertexUniform;
2096 }
2097
2098 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2099 {
2100 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2101 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2102 if (entry != linkedUniforms.end())
2103 {
2104 const sh::Uniform &vertexUniform = *entry->second;
2105 const std::string &uniformName = "uniform " + vertexUniform.name;
2106 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2107 {
2108 return false;
2109 }
2110 }
2111 }
2112
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002113 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002114 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002115 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 {
2117 return false;
2118 }
2119 }
2120
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002121 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002122 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002123 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002124 {
2125 return false;
2126 }
2127 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002128
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002129 return true;
2130}
2131
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002132int totalRegisterCount(const sh::Uniform &uniform)
2133{
2134 int registerCount = 0;
2135
2136 if (!uniform.fields.empty())
2137 {
2138 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2139 {
2140 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2141 }
2142 }
2143 else
2144 {
2145 registerCount = 1;
2146 }
2147
2148 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2149}
2150
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002151bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002152{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002153 if (!constant.fields.empty())
2154 {
2155 if (constant.arraySize > 0)
2156 {
2157 unsigned int elementRegisterIndex = constant.registerIndex;
2158
2159 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2160 {
2161 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2162 {
2163 const sh::Uniform &field = constant.fields[fieldIndex];
2164 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2165 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2166 if (!defineUniform(shader, fieldUniform, infoLog))
2167 {
2168 return false;
2169 }
2170 elementRegisterIndex += totalRegisterCount(field);
2171 }
2172 }
2173 }
2174 else
2175 {
2176 unsigned int fieldRegisterIndex = constant.registerIndex;
2177
2178 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2179 {
2180 const sh::Uniform &field = constant.fields[fieldIndex];
2181 const std::string &uniformName = constant.name + "." + field.name;
2182
2183 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2184 fieldUniform.fields = field.fields;
2185
2186 if (!defineUniform(shader, fieldUniform, infoLog))
2187 {
2188 return false;
2189 }
2190 fieldRegisterIndex += totalRegisterCount(field);
2191 }
2192 }
2193
2194 return true;
2195 }
2196
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002197 if (constant.type == GL_SAMPLER_2D ||
2198 constant.type == GL_SAMPLER_CUBE)
2199 {
2200 unsigned int samplerIndex = constant.registerIndex;
2201
2202 do
2203 {
2204 if (shader == GL_VERTEX_SHADER)
2205 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002206 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002207 {
2208 mSamplersVS[samplerIndex].active = true;
2209 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2210 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2211 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2212 }
2213 else
2214 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002215 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002216 return false;
2217 }
2218 }
2219 else if (shader == GL_FRAGMENT_SHADER)
2220 {
2221 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2222 {
2223 mSamplersPS[samplerIndex].active = true;
2224 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2225 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2226 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2227 }
2228 else
2229 {
2230 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2231 return false;
2232 }
2233 }
2234 else UNREACHABLE();
2235
2236 samplerIndex++;
2237 }
2238 while (samplerIndex < constant.registerIndex + constant.arraySize);
2239 }
2240
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002241 Uniform *uniform = NULL;
2242 GLint location = getUniformLocation(constant.name);
2243
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002244 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002245 {
2246 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002247 }
2248 else
2249 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002250 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002251 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002252
2253 if (!uniform)
2254 {
2255 return false;
2256 }
2257
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002258 if (shader == GL_FRAGMENT_SHADER)
2259 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002260 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002261 }
2262 else if (shader == GL_VERTEX_SHADER)
2263 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002264 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002265 }
2266 else UNREACHABLE();
2267
2268 if (location >= 0)
2269 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002270 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002271 }
2272
2273 mUniforms.push_back(uniform);
2274 unsigned int uniformIndex = mUniforms.size() - 1;
2275
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002276 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002277 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002278 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002279 }
2280
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002281 if (shader == GL_VERTEX_SHADER)
2282 {
2283 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2284 {
2285 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2286 return false;
2287 }
2288 }
2289 else if (shader == GL_FRAGMENT_SHADER)
2290 {
2291 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2292 {
2293 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2294 return false;
2295 }
2296 }
2297 else UNREACHABLE();
2298
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002299 return true;
2300}
2301
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002302bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2303{
2304 const char* blockName = vertexInterfaceBlock.name.c_str();
2305
2306 // validate blocks for the same member types
2307 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2308 {
2309 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2310 return false;
2311 }
2312
2313 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2314 {
2315 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2316 return false;
2317 }
2318
2319 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2320 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2321 {
2322 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2323 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2324
2325 if (vertexMember.name != fragmentMember.name)
2326 {
2327 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2328 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2329 return false;
2330 }
2331
2332 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2333 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2334 {
2335 return false;
2336 }
2337 }
2338
2339 return true;
2340}
2341
2342bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2343{
2344 // Check that interface blocks defined in the vertex and fragment shaders are identical
2345 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2346 UniformBlockMap linkedUniformBlocks;
2347
2348 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2349 {
2350 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2351 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2352 }
2353
2354 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2355 {
2356 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2357 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2358 if (entry != linkedUniformBlocks.end())
2359 {
2360 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2361 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2362 {
2363 return false;
2364 }
2365 }
2366 }
2367
2368 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2369 {
2370 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2371 {
2372 return false;
2373 }
2374 }
2375
2376 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2377 {
2378 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2379 {
2380 return false;
2381 }
2382 }
2383
2384 return true;
2385}
2386
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002387void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2388{
2389 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2390 {
2391 const sh::Uniform &uniform = uniforms[uniformIndex];
2392
2393 if (!uniform.fields.empty())
2394 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002395 if (uniform.arraySize > 0)
2396 {
2397 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2398 {
2399 const std::string uniformElementName = uniform.name + "[" + str(arrayElement) + "]";
2400 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2401 }
2402 }
2403 else
2404 {
2405 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2406 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002407 }
2408 else
2409 {
2410 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2411 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2412 blockIndex, **blockInfoItr);
2413
2414 // add to uniform list, but not index, since uniform block uniforms have no location
2415 blockUniformIndexes->push_back(mUniforms.size());
2416 mUniforms.push_back(newUniform);
2417 (*blockInfoItr)++;
2418 }
2419 }
2420}
2421
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002422bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2423{
2424 // create uniform block entries if they do not exist
2425 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2426 {
2427 std::vector<unsigned int> blockUniformIndexes;
2428 const unsigned int blockIndex = mUniformBlocks.size();
2429
2430 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002431 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2432 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002433
2434 // create all the uniform blocks
2435 if (interfaceBlock.arraySize > 0)
2436 {
2437 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2438 {
2439 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2440 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2441 mUniformBlocks.push_back(newUniformBlock);
2442 }
2443 }
2444 else
2445 {
2446 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2447 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2448 mUniformBlocks.push_back(newUniformBlock);
2449 }
2450 }
2451
2452 // Assign registers to the uniform blocks
2453 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2454 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2455 ASSERT(blockIndex != GL_INVALID_INDEX);
2456 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2457
2458 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2459 {
2460 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2461 ASSERT(uniformBlock->name == interfaceBlock.name);
2462
2463 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2464 {
2465 return false;
2466 }
2467 }
2468
2469 return true;
2470}
2471
2472bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2473{
2474 if (shader == GL_VERTEX_SHADER)
2475 {
2476 uniformBlock->vsRegisterIndex = registerIndex;
2477 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2478
2479 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2480 {
2481 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2482 return false;
2483 }
2484 }
2485 else if (shader == GL_FRAGMENT_SHADER)
2486 {
2487 uniformBlock->psRegisterIndex = registerIndex;
2488 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2489
2490 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2491 {
2492 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2493 return false;
2494 }
2495 }
2496 else UNREACHABLE();
2497
2498 return true;
2499}
2500
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002501std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2502{
2503 // for now we only handle point sprite emulation
2504 ASSERT(usesPointSpriteEmulation());
2505 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2506}
2507
2508std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2509{
2510 ASSERT(registers >= 0);
2511 ASSERT(vertexShader->mUsesPointSize);
2512 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2513
2514 std::string geomHLSL;
2515
2516 std::string varyingSemantic = "TEXCOORD";
2517
2518 std::string fragCoordSemantic;
2519 std::string pointCoordSemantic;
2520
2521 int reservedRegisterIndex = registers;
2522
2523 if (fragmentShader->mUsesFragCoord)
2524 {
2525 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2526 }
2527
2528 if (fragmentShader->mUsesPointCoord)
2529 {
2530 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2531 }
2532
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002533 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2534 "\n"
2535 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002536 "{\n";
2537
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002538 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002539
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002540 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002541
2542 if (fragmentShader->mUsesFragCoord)
2543 {
2544 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2545 }
2546
2547 geomHLSL += " float gl_PointSize : PSIZE;\n"
2548 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002549 "};\n"
2550 "\n"
2551 "struct GS_OUTPUT\n"
2552 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002553
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002554 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002555
2556 if (fragmentShader->mUsesFragCoord)
2557 {
2558 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2559 }
2560
2561 if (fragmentShader->mUsesPointCoord)
2562 {
2563 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2564 }
2565
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002566 geomHLSL += " float gl_PointSize : PSIZE;\n"
2567 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002568 "};\n"
2569 "\n"
2570 "static float2 pointSpriteCorners[] = \n"
2571 "{\n"
2572 " float2( 0.5f, -0.5f),\n"
2573 " float2( 0.5f, 0.5f),\n"
2574 " float2(-0.5f, -0.5f),\n"
2575 " float2(-0.5f, 0.5f)\n"
2576 "};\n"
2577 "\n"
2578 "static float2 pointSpriteTexcoords[] = \n"
2579 "{\n"
2580 " float2(1.0f, 1.0f),\n"
2581 " float2(1.0f, 0.0f),\n"
2582 " float2(0.0f, 1.0f),\n"
2583 " float2(0.0f, 0.0f)\n"
2584 "};\n"
2585 "\n"
2586 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2587 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2588 "\n"
2589 "[maxvertexcount(4)]\n"
2590 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2591 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002592 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2593 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002594
2595 for (int r = 0; r < registers; r++)
2596 {
2597 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2598 }
2599
2600 if (fragmentShader->mUsesFragCoord)
2601 {
2602 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2603 }
2604
2605 geomHLSL += " \n"
2606 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2607 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002608 " 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 +00002609
2610 for (int corner = 0; corner < 4; corner++)
2611 {
2612 geomHLSL += " \n"
2613 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2614
2615 if (fragmentShader->mUsesPointCoord)
2616 {
2617 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2618 }
2619
2620 geomHLSL += " outStream.Append(output);\n";
2621 }
2622
2623 geomHLSL += " \n"
2624 " outStream.RestartStrip();\n"
2625 "}\n";
2626
2627 return geomHLSL;
2628}
2629
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002630// This method needs to match OutputHLSL::decorate
2631std::string ProgramBinary::decorateAttribute(const std::string &name)
2632{
2633 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2634 {
2635 return "_" + name;
2636 }
2637
2638 return name;
2639}
2640
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002641bool ProgramBinary::isValidated() const
2642{
2643 return mValidated;
2644}
2645
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002646void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002647{
2648 // Skip over inactive attributes
2649 unsigned int activeAttribute = 0;
2650 unsigned int attribute;
2651 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2652 {
2653 if (mLinkedAttribute[attribute].name.empty())
2654 {
2655 continue;
2656 }
2657
2658 if (activeAttribute == index)
2659 {
2660 break;
2661 }
2662
2663 activeAttribute++;
2664 }
2665
2666 if (bufsize > 0)
2667 {
2668 const char *string = mLinkedAttribute[attribute].name.c_str();
2669
2670 strncpy(name, string, bufsize);
2671 name[bufsize - 1] = '\0';
2672
2673 if (length)
2674 {
2675 *length = strlen(name);
2676 }
2677 }
2678
2679 *size = 1; // Always a single 'type' instance
2680
2681 *type = mLinkedAttribute[attribute].type;
2682}
2683
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002684GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002685{
2686 int count = 0;
2687
2688 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2689 {
2690 if (!mLinkedAttribute[attributeIndex].name.empty())
2691 {
2692 count++;
2693 }
2694 }
2695
2696 return count;
2697}
2698
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002699GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002700{
2701 int maxLength = 0;
2702
2703 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2704 {
2705 if (!mLinkedAttribute[attributeIndex].name.empty())
2706 {
2707 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2708 }
2709 }
2710
2711 return maxLength;
2712}
2713
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002714void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002715{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002716 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002717
2718 if (bufsize > 0)
2719 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002720 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002721
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002722 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002723 {
2724 string += "[0]";
2725 }
2726
2727 strncpy(name, string.c_str(), bufsize);
2728 name[bufsize - 1] = '\0';
2729
2730 if (length)
2731 {
2732 *length = strlen(name);
2733 }
2734 }
2735
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002736 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002737
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002738 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002739}
2740
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002741GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002742{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002743 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002744}
2745
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002746GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002747{
2748 int maxLength = 0;
2749
2750 unsigned int numUniforms = mUniforms.size();
2751 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2752 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002753 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002754 {
2755 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2756 if (mUniforms[uniformIndex]->isArray())
2757 {
2758 length += 3; // Counting in "[0]".
2759 }
2760 maxLength = std::max(length, maxLength);
2761 }
2762 }
2763
2764 return maxLength;
2765}
2766
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002767GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2768{
2769 const gl::Uniform& uniform = *mUniforms[index];
2770
2771 switch (pname)
2772 {
2773 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2774 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002775 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 +00002776 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002777
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002778 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2779 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2780 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2781 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002782
2783 default:
2784 UNREACHABLE();
2785 break;
2786 }
2787 return 0;
2788}
2789
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002790void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2791{
2792 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2793
2794 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2795
2796 if (bufSize > 0)
2797 {
2798 std::string string = uniformBlock.name;
2799
2800 if (uniformBlock.isArrayElement())
2801 {
2802 string += "[" + str(uniformBlock.elementIndex) + "]";
2803 }
2804
2805 strncpy(uniformBlockName, string.c_str(), bufSize);
2806 uniformBlockName[bufSize - 1] = '\0';
2807
2808 if (length)
2809 {
2810 *length = strlen(uniformBlockName);
2811 }
2812 }
2813}
2814
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002815void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2816{
2817 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2818
2819 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2820
2821 switch (pname)
2822 {
2823 case GL_UNIFORM_BLOCK_DATA_SIZE:
2824 *params = static_cast<GLint>(uniformBlock.dataSize);
2825 break;
2826 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002827 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002828 break;
2829 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2830 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2831 break;
2832 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2833 {
2834 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2835 {
2836 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2837 }
2838 }
2839 break;
2840 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2841 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2842 break;
2843 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2844 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2845 break;
2846 default: UNREACHABLE();
2847 }
2848}
2849
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002850GLuint ProgramBinary::getActiveUniformBlockCount() const
2851{
2852 return mUniformBlocks.size();
2853}
2854
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002855GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2856{
2857 unsigned int maxLength = 0;
2858
2859 unsigned int numUniformBlocks = mUniformBlocks.size();
2860 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2861 {
2862 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2863 if (!uniformBlock.name.empty())
2864 {
2865 const unsigned int length = uniformBlock.name.length() + 1;
2866
2867 // Counting in "[0]".
2868 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2869
2870 maxLength = std::max(length + arrayLength, maxLength);
2871 }
2872 }
2873
2874 return maxLength;
2875}
2876
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002877void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002878{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002879 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002880 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002881 {
2882 mValidated = false;
2883 }
2884 else
2885 {
2886 mValidated = true;
2887 }
2888}
2889
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002890bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002891{
2892 // if any two active samplers in a program are of different types, but refer to the same
2893 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2894 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2895
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002896 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002897 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002898
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002899 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002900 {
2901 textureUnitType[i] = TEXTURE_UNKNOWN;
2902 }
2903
2904 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2905 {
2906 if (mSamplersPS[i].active)
2907 {
2908 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2909
2910 if (unit >= maxCombinedTextureImageUnits)
2911 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002912 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002913 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002914 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002915 }
2916
2917 return false;
2918 }
2919
2920 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2921 {
2922 if (mSamplersPS[i].textureType != textureUnitType[unit])
2923 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002924 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002925 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002926 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002927 }
2928
2929 return false;
2930 }
2931 }
2932 else
2933 {
2934 textureUnitType[unit] = mSamplersPS[i].textureType;
2935 }
2936 }
2937 }
2938
2939 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2940 {
2941 if (mSamplersVS[i].active)
2942 {
2943 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2944
2945 if (unit >= maxCombinedTextureImageUnits)
2946 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002947 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002948 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002949 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002950 }
2951
2952 return false;
2953 }
2954
2955 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2956 {
2957 if (mSamplersVS[i].textureType != textureUnitType[unit])
2958 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002959 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002960 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002961 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002962 }
2963
2964 return false;
2965 }
2966 }
2967 else
2968 {
2969 textureUnitType[unit] = mSamplersVS[i].textureType;
2970 }
2971 }
2972 }
2973
2974 return true;
2975}
2976
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002977ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2978{
2979}
2980
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002981struct AttributeSorter
2982{
2983 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2984 : originalIndices(semanticIndices)
2985 {
2986 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2987 {
2988 indices[i] = i;
2989 }
2990
2991 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2992 }
2993
2994 bool operator()(int a, int b)
2995 {
2996 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2997 }
2998
2999 int indices[MAX_VERTEX_ATTRIBS];
3000 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3001};
3002
3003void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3004{
3005 AttributeSorter sorter(mSemanticIndex);
3006
3007 int oldIndices[MAX_VERTEX_ATTRIBS];
3008 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3009
3010 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3011 {
3012 oldIndices[i] = mSemanticIndex[i];
3013 oldTranslatedAttributes[i] = attributes[i];
3014 }
3015
3016 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3017 {
3018 int oldIndex = sorter.indices[i];
3019 sortedSemanticIndices[i] = oldIndices[oldIndex];
3020 attributes[i] = oldTranslatedAttributes[oldIndex];
3021 }
3022}
3023
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003024}