blob: 2602234a3aa5e97251b1727ce05f905dff656f0c [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
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000191void Program::release()
192{
193 mRefCount--;
194
195 if (mRefCount == 0 && mDeleteStatus)
196 {
197 mResourceManager->deleteProgram(mHandle);
198 }
199}
200
201void Program::addRef()
202{
203 mRefCount++;
204}
205
206unsigned int Program::getRefCount() const
207{
208 return mRefCount;
209}
210
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000211unsigned int Program::getSerial() const
212{
213 return mSerial;
214}
215
216unsigned int Program::issueSerial()
217{
218 return mCurrentSerial++;
219}
220
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000221int Program::getInfoLogLength() const
222{
223 if (mProgramBinary)
224 {
225 return mProgramBinary->getInfoLogLength();
226 }
227 else
228 {
229 return 0;
230 }
231}
232
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000233void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
234{
235 if (mProgramBinary)
236 {
237 return mProgramBinary->getInfoLog(bufSize, length, infoLog);
238 }
239 else
240 {
241 if (bufSize > 0)
242 {
243 infoLog[0] = '\0';
244 }
245
246 if (length)
247 {
248 *length = 0;
249 }
250 }
251}
252
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000253void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
254{
255 int total = 0;
256
257 if (mVertexShader)
258 {
259 if (total < maxCount)
260 {
261 shaders[total] = mVertexShader->getHandle();
262 }
263
264 total++;
265 }
266
267 if (mFragmentShader)
268 {
269 if (total < maxCount)
270 {
271 shaders[total] = mFragmentShader->getHandle();
272 }
273
274 total++;
275 }
276
277 if (count)
278 {
279 *count = total;
280 }
281}
282
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000283void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
284{
285 if (mProgramBinary)
286 {
287 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
288 }
289 else
290 {
291 if (bufsize > 0)
292 {
293 name[0] = '\0';
294 }
295
296 if (length)
297 {
298 *length = 0;
299 }
300
301 *type = GL_NONE;
302 *size = 1;
303 }
304}
305
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000306GLint Program::getActiveAttributeCount()
307{
308 if (mProgramBinary)
309 {
310 return mProgramBinary->getActiveAttributeCount();
311 }
312 else
313 {
314 return 0;
315 }
316}
317
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000318GLint Program::getActiveAttributeMaxLength()
319{
320 if (mProgramBinary)
321 {
322 return mProgramBinary->getActiveAttributeMaxLength();
323 }
324 else
325 {
326 return 0;
327 }
328}
329
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000330void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
331{
332 if (mProgramBinary)
333 {
334 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
335 }
336 else
337 {
338 if (bufsize > 0)
339 {
340 name[0] = '\0';
341 }
342
343 if (length)
344 {
345 *length = 0;
346 }
347
348 *size = 0;
349 *type = GL_NONE;
350 }
351}
352
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000353GLint Program::getActiveUniformCount()
354{
355 if (mProgramBinary)
356 {
357 return mProgramBinary->getActiveUniformCount();
358 }
359 else
360 {
361 return 0;
362 }
363}
364
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000365GLint Program::getActiveUniformMaxLength()
366{
367 if (mProgramBinary)
368 {
369 return mProgramBinary->getActiveUniformMaxLength();
370 }
371 else
372 {
373 return 0;
374 }
375}
376
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377void Program::flagForDeletion()
378{
379 mDeleteStatus = true;
380}
381
382bool Program::isFlaggedForDeletion() const
383{
384 return mDeleteStatus;
385}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000386
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000387bool Program::isValidated() const
388{
389 if (mProgramBinary)
390 {
391 return mProgramBinary->isValidated();
392 }
393 else
394 {
395 return false;
396 }
397}
398
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000399}