blob: 184a02c4159e1c75245cb0c252b081fbd644173c [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Program.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000013#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000015#include "libGLESv2/main.h"
16#include "libGLESv2/Shader.h"
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000017#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
daniel@transgaming.com87891f72011-06-01 15:28:35 +000019#include <string>
20
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021namespace gl
22{
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000023unsigned int Program::mCurrentSerial = 1;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000024
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000025AttributeBindings::AttributeBindings()
26{
27}
28
29AttributeBindings::~AttributeBindings()
30{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000031}
32
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000033Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
34{
35 mFragmentShader = NULL;
36 mVertexShader = NULL;
37 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038 mDeleteStatus = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000039 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000040}
41
42Program::~Program()
43{
44 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000045
46 if (mVertexShader != NULL)
47 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000048 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000049 }
50
51 if (mFragmentShader != NULL)
52 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000053 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000054 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055}
56
57bool Program::attachShader(Shader *shader)
58{
59 if (shader->getType() == GL_VERTEX_SHADER)
60 {
61 if (mVertexShader)
62 {
63 return false;
64 }
65
66 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000067 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000068 }
69 else if (shader->getType() == GL_FRAGMENT_SHADER)
70 {
71 if (mFragmentShader)
72 {
73 return false;
74 }
75
76 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000077 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000078 }
79 else UNREACHABLE();
80
81 return true;
82}
83
84bool Program::detachShader(Shader *shader)
85{
86 if (shader->getType() == GL_VERTEX_SHADER)
87 {
88 if (mVertexShader != shader)
89 {
90 return false;
91 }
92
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000093 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094 mVertexShader = NULL;
95 }
96 else if (shader->getType() == GL_FRAGMENT_SHADER)
97 {
98 if (mFragmentShader != shader)
99 {
100 return false;
101 }
102
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000103 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 mFragmentShader = NULL;
105 }
106 else UNREACHABLE();
107
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108 return true;
109}
110
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000111int Program::getAttachedShadersCount() const
112{
113 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
114}
115
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000116void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
117{
118 if (index < MAX_VERTEX_ATTRIBS)
119 {
120 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
121 {
122 mAttributeBinding[i].erase(name);
123 }
124
125 mAttributeBinding[index].insert(name);
126 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000127}
128
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129void Program::bindAttributeLocation(GLuint index, const char *name)
130{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000131 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132}
133
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
135// compiling them into binaries, determining the attribute mappings, and collecting
136// a list of uniforms
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000137void Program::link()
138{
139 unlink(false);
140
141 mProgramBinary = new ProgramBinary;
142 if (!mProgramBinary->link(mAttributeBindings, mFragmentShader, mVertexShader))
143 {
144 unlink(false);
145 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000146}
147
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000148int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000149{
150 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
151 {
152 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
153 {
154 return location;
155 }
156 }
157
158 return -1;
159}
160
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000161// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162void Program::unlink(bool destroy)
163{
164 if (destroy) // Object being destructed
165 {
166 if (mFragmentShader)
167 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000168 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 mFragmentShader = NULL;
170 }
171
172 if (mVertexShader)
173 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000174 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175 mVertexShader = NULL;
176 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 }
178
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000179 if (mProgramBinary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 {
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000181 delete mProgramBinary;
182 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184}
185
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000186ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187{
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000188 return mProgramBinary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000191void Program::setProgramBinary(ProgramBinary *programBinary)
192{
193 unlink(false);
194 mProgramBinary = programBinary;
195}
196
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000197void Program::release()
198{
199 mRefCount--;
200
201 if (mRefCount == 0 && mDeleteStatus)
202 {
203 mResourceManager->deleteProgram(mHandle);
204 }
205}
206
207void Program::addRef()
208{
209 mRefCount++;
210}
211
212unsigned int Program::getRefCount() const
213{
214 return mRefCount;
215}
216
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000217unsigned int Program::getSerial() const
218{
219 return mSerial;
220}
221
222unsigned int Program::issueSerial()
223{
224 return mCurrentSerial++;
225}
226
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000227int Program::getInfoLogLength() const
228{
229 if (mProgramBinary)
230 {
231 return mProgramBinary->getInfoLogLength();
232 }
233 else
234 {
235 return 0;
236 }
237}
238
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000239void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
240{
241 if (mProgramBinary)
242 {
243 return mProgramBinary->getInfoLog(bufSize, length, infoLog);
244 }
245 else
246 {
247 if (bufSize > 0)
248 {
249 infoLog[0] = '\0';
250 }
251
252 if (length)
253 {
254 *length = 0;
255 }
256 }
257}
258
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000259void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
260{
261 int total = 0;
262
263 if (mVertexShader)
264 {
265 if (total < maxCount)
266 {
267 shaders[total] = mVertexShader->getHandle();
268 }
269
270 total++;
271 }
272
273 if (mFragmentShader)
274 {
275 if (total < maxCount)
276 {
277 shaders[total] = mFragmentShader->getHandle();
278 }
279
280 total++;
281 }
282
283 if (count)
284 {
285 *count = total;
286 }
287}
288
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000289void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
290{
291 if (mProgramBinary)
292 {
293 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
294 }
295 else
296 {
297 if (bufsize > 0)
298 {
299 name[0] = '\0';
300 }
301
302 if (length)
303 {
304 *length = 0;
305 }
306
307 *type = GL_NONE;
308 *size = 1;
309 }
310}
311
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000312GLint Program::getActiveAttributeCount()
313{
314 if (mProgramBinary)
315 {
316 return mProgramBinary->getActiveAttributeCount();
317 }
318 else
319 {
320 return 0;
321 }
322}
323
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000324GLint Program::getActiveAttributeMaxLength()
325{
326 if (mProgramBinary)
327 {
328 return mProgramBinary->getActiveAttributeMaxLength();
329 }
330 else
331 {
332 return 0;
333 }
334}
335
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000336void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
337{
338 if (mProgramBinary)
339 {
340 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
341 }
342 else
343 {
344 if (bufsize > 0)
345 {
346 name[0] = '\0';
347 }
348
349 if (length)
350 {
351 *length = 0;
352 }
353
354 *size = 0;
355 *type = GL_NONE;
356 }
357}
358
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000359GLint Program::getActiveUniformCount()
360{
361 if (mProgramBinary)
362 {
363 return mProgramBinary->getActiveUniformCount();
364 }
365 else
366 {
367 return 0;
368 }
369}
370
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000371GLint Program::getActiveUniformMaxLength()
372{
373 if (mProgramBinary)
374 {
375 return mProgramBinary->getActiveUniformMaxLength();
376 }
377 else
378 {
379 return 0;
380 }
381}
382
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383void Program::flagForDeletion()
384{
385 mDeleteStatus = true;
386}
387
388bool Program::isFlaggedForDeletion() const
389{
390 return mDeleteStatus;
391}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000392
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000393bool Program::isValidated() const
394{
395 if (mProgramBinary)
396 {
397 return mProgramBinary->isValidated();
398 }
399 else
400 {
401 return false;
402 }
403}
404
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000405}