7c1282bdd67bdf17f43ea4a49784382d57a4b8a8
[platform/core/uifw/dali-core.git] / dali / internal / render / shaders / program.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/render/shaders/program.h>
20
21 // EXTERNAL INCLUDES
22 #include <iomanip>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/common/dali-vector.h>
27 #include <dali/public-api/common/constants.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/internal/common/shader-data.h>
30 #include <dali/integration-api/gl-defines.h>
31 #include <dali/internal/render/common/performance-monitor.h>
32 #include <dali/internal/render/shaders/program-cache.h>
33 #include <dali/internal/render/gl-resources/gl-call-debug.h>
34
35 namespace
36 {
37 void LogWithLineNumbers( const char * source )
38 {
39   unsigned int lineNumber = 0u;
40   const char *prev = source;
41   const char *ptr = prev;
42
43   while( true )
44   {
45     if(lineNumber > 200u)
46     {
47       break;
48     }
49     // seek the next end of line or end of text
50     while( *ptr!='\n' && *ptr != '\0' )
51     {
52       ++ptr;
53     }
54
55     std::string line( prev, ptr-prev );
56     Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, "%4d %s\n", lineNumber, line.c_str());
57
58     if( *ptr == '\0' )
59     {
60       break;
61     }
62     prev = ++ptr;
63     ++lineNumber;
64   }
65 }
66
67 } //namespace
68
69 namespace Dali
70 {
71
72 namespace Internal
73 {
74
75 // LOCAL STUFF
76 namespace
77 {
78
79 const char* gStdAttribs[ Program::ATTRIB_TYPE_LAST ] =
80 {
81   "aPosition",    // ATTRIB_POSITION
82   "aNormal",      // ATTRIB_NORMAL
83   "aTexCoord",    // ATTRIB_TEXCOORD
84   "aColor",       // ATTRIB_COLOR
85   "aBoneWeights", // ATTRIB_BONE_WEIGHTS
86   "aBoneIndices"  // ATTRIB_BONE_INDICES
87 };
88
89 const char* gStdUniforms[ Program::UNIFORM_TYPE_LAST ] =
90 {
91   "uMvpMatrix",           // UNIFORM_MVP_MATRIX
92   "uModelView",           // UNIFORM_MODELVIEW_MATRIX
93   "uProjection",          // UNIFORM_PROJECTION_MATRIX
94   "uModelMatrix",         // UNIFORM_MODEL_MATRIX,
95   "uViewMatrix",          // UNIFORM_VIEW_MATRIX,
96   "uNormalMatrix",        // UNIFORM_NORMAL_MATRIX
97   "uColor",               // UNIFORM_COLOR
98   "uCustomTextureCoords", // UNIFORM_CUSTOM_TEXTURE_COORDS
99   "sTexture",             // UNIFORM_SAMPLER
100   "sTextureRect",         // UNIFORM_SAMPLER_RECT
101   "sEffect",              // UNIFORM_EFFECT_SAMPLER
102   "sEffectRect",          // UNIFORM_EFFECT_SAMPLER_RECT
103   "uTimeDelta",           // UNIFORM_TIME_DELTA
104   "sOpacityTexture",      // UNIFORM_SAMPLER_OPACITY
105   "sNormalMapTexture",    // UNIFORM_SAMPLER_NORMAL_MAP
106   "uSize"                 // UNIFORM_SIZE
107 };
108
109 }  // <unnamed> namespace
110
111 // IMPLEMENTATION
112
113 Program* Program::New( ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
114 {
115   size_t shaderHash = shaderData->GetHashValue();
116   Program* program = cache.GetProgram( shaderHash );
117
118   if( NULL == program )
119   {
120     // program not found so create it
121     program = new Program( cache, shaderData, modifiesGeometry );
122
123     // we want to lazy load programs so dont do a Load yet, it gets done in Use()
124
125     cache.AddProgram( shaderHash, program );
126   }
127
128   return program;
129 }
130
131 void Program::Use()
132 {
133   if ( !mLinked )
134   {
135     Load();
136   }
137
138   if ( mLinked )
139   {
140     if ( this != mCache.GetCurrentProgram() )
141     {
142       LOG_GL( "UseProgram(%d)\n", mProgramId );
143       CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(mProgramId) );
144
145       mCache.SetCurrentProgram( this );
146     }
147   }
148 }
149
150 bool Program::IsUsed()
151 {
152   return ( this == mCache.GetCurrentProgram() );
153 }
154
155 GLint Program::GetAttribLocation( AttribType type )
156 {
157   DALI_ASSERT_DEBUG(type != ATTRIB_UNKNOWN);
158
159   return GetCustomAttributeLocation( type );
160 }
161
162 unsigned int Program::RegisterCustomAttribute( const std::string& name )
163 {
164   unsigned int index = 0;
165   // find the value from cache
166   for( ;index < mAttributeLocations.size(); ++index )
167   {
168     if( mAttributeLocations[ index ].first == name )
169     {
170       // name found so return index
171       return index;
172     }
173   }
174   // if we get here, index is one past end so push back the new name
175   mAttributeLocations.push_back( std::make_pair( name, ATTRIB_UNKNOWN ) );
176   return index;
177 }
178
179 GLint Program::GetCustomAttributeLocation( unsigned int attributeIndex )
180 {
181   // debug check that index is within name cache
182   DALI_ASSERT_DEBUG( mAttributeLocations.size() > attributeIndex );
183
184   // check if we have already queried the location of the attribute
185   GLint location = mAttributeLocations[ attributeIndex ].second;
186
187   if( location == ATTRIB_UNKNOWN )
188   {
189     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, mAttributeLocations[ attributeIndex ].first.c_str() ) );
190
191     mAttributeLocations[ attributeIndex ].second = location;
192     LOG_GL( "GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[ attributeIndex ].first.c_str(), mAttributeLocations[ attributeIndex ].second );
193   }
194
195   return location;
196 }
197
198
199 unsigned int Program::RegisterUniform( const std::string& name )
200 {
201   unsigned int index = 0;
202   // find the value from cache
203   for( ;index < mUniformLocations.size(); ++index )
204   {
205     if( mUniformLocations[ index ].first == name )
206     {
207       // name found so return index
208       return index;
209     }
210   }
211   // if we get here, index is one past end so push back the new name
212   mUniformLocations.push_back( std::make_pair( name, UNIFORM_NOT_QUERIED ) );
213   return index;
214 }
215
216 GLint Program::GetUniformLocation( unsigned int uniformIndex )
217 {
218   // debug check that index is within name cache
219   DALI_ASSERT_DEBUG( mUniformLocations.size() > uniformIndex );
220
221   // check if we have already queried the location of the uniform
222   GLint location = mUniformLocations[ uniformIndex ].second;
223
224   if( location == UNIFORM_NOT_QUERIED )
225   {
226     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.c_str() ) );
227
228     mUniformLocations[ uniformIndex ].second = location;
229     LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.c_str(), mUniformLocations[ uniformIndex ].second );
230   }
231
232   return location;
233 }
234
235 void Program::SetUniform1i( GLint location, GLint value0 )
236 {
237   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
238
239   if( UNIFORM_UNKNOWN == location )
240   {
241     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
242     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
243     // specified uniform variable will not be changed.following opengl silently do nothing
244     return;
245   }
246
247   // check if uniform location fits the cache
248   if( location >= MAX_UNIFORM_CACHE_SIZE )
249   {
250     // not cached, make the gl call
251     LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
252     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
253   }
254   else
255   {
256     // check if the value is different from what's already been set
257     if( value0 != mUniformCacheInt[ location ] )
258     {
259       // make the gl call
260       LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
261       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
262       // update cache
263       mUniformCacheInt[ location ] = value0;
264     }
265   }
266 }
267
268 void Program::SetUniform4i( GLint location, GLint value0, GLint value1, GLint value2, GLint value3 )
269 {
270   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
271
272   if( UNIFORM_UNKNOWN == location )
273   {
274     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
275     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
276     // specified uniform variable will not be changed.following opengl silently do nothing
277     return;
278   }
279
280   // Not caching these as based on current analysis this is not called that often by our shaders
281   LOG_GL( "Uniform4i(%d,%d,%d,%d,%d)\n", location, value0, value1, value2, value3 );
282   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4i( location, value0, value1, value2, value3 ) );
283 }
284
285 void Program::SetUniform1f( GLint location, GLfloat value0 )
286 {
287   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
288
289   if( UNIFORM_UNKNOWN == location )
290   {
291     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
292     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
293     // specified uniform variable will not be changed.following opengl silently do nothing
294     return;
295   }
296
297   // check if uniform location fits the cache
298   if( location >= MAX_UNIFORM_CACHE_SIZE )
299   {
300     // not cached, make the gl call
301     LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
302     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
303   }
304   else
305   {
306     // check if the same value has already been set, reset if it is different
307     if( ( fabsf(value0 - mUniformCacheFloat[ location ]) >= Math::MACHINE_EPSILON_1 ) )
308     {
309       // make the gl call
310       LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
311       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
312
313       // update cache
314       mUniformCacheFloat[ location ] = value0;
315     }
316   }
317 }
318
319 void Program::SetUniform2f( GLint location, GLfloat value0, GLfloat value1 )
320 {
321   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
322
323   if( UNIFORM_UNKNOWN == location )
324   {
325     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
326     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
327     // specified uniform variable will not be changed.following opengl silently do nothing
328     return;
329   }
330
331   // Not caching these as based on current analysis this is not called that often by our shaders
332   LOG_GL( "Uniform2f(%d,%f,%f)\n", location, value0, value1 );
333   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform2f( location, value0, value1 ) );
334 }
335
336 void Program::SetSizeUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
337 {
338   if( ( fabsf(value0 - mSizeUniformCache.x) >= Math::MACHINE_EPSILON_1 )||
339       ( fabsf(value1 - mSizeUniformCache.y) >= Math::MACHINE_EPSILON_1 )||
340       ( fabsf(value2 - mSizeUniformCache.z) >= Math::MACHINE_EPSILON_1 ) )
341   {
342     mSizeUniformCache.x = value0;
343     mSizeUniformCache.y = value1;
344     mSizeUniformCache.z = value2;
345     SetUniform3f( location, value0, value1, value2 );
346   }
347 }
348
349 void Program::SetUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
350 {
351   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
352
353   if( UNIFORM_UNKNOWN == location )
354   {
355     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
356     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
357     // specified uniform variable will not be changed.following opengl silently do nothing
358     return;
359   }
360
361   // Not caching these as based on current analysis this is not called that often by our shaders
362   LOG_GL( "Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2 );
363   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform3f( location, value0, value1, value2 ) );
364 }
365
366 void Program::SetUniform4f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3 )
367 {
368   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
369
370   if( UNIFORM_UNKNOWN == location )
371   {
372     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
373     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
374     // specified uniform variable will not be changed.following opengl silently do nothing
375     return;
376   }
377
378   // check if uniform location fits the cache
379   if( location >= MAX_UNIFORM_CACHE_SIZE )
380   {
381     // not cached, make the gl call
382     LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
383     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
384   }
385   else
386   {
387     // check if the same value has already been set, reset if any component is different
388     // checking index 3 first because we're often animating alpha (rgba)
389     if( ( fabsf(value3 - mUniformCacheFloat4[ location ][ 3 ]) >= Math::MACHINE_EPSILON_1 )||
390         ( fabsf(value0 - mUniformCacheFloat4[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
391         ( fabsf(value1 - mUniformCacheFloat4[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 )||
392         ( fabsf(value2 - mUniformCacheFloat4[ location ][ 2 ]) >= Math::MACHINE_EPSILON_1 ) )
393     {
394       // make the gl call
395       LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
396       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
397       // update cache
398       mUniformCacheFloat4[ location ][ 0 ] = value0;
399       mUniformCacheFloat4[ location ][ 1 ] = value1;
400       mUniformCacheFloat4[ location ][ 2 ] = value2;
401       mUniformCacheFloat4[ location ][ 3 ] = value3;
402     }
403   }
404 }
405
406 void Program::SetUniformMatrix4fv( GLint location, GLsizei count, const GLfloat* value )
407 {
408   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
409
410   if( UNIFORM_UNKNOWN == location )
411   {
412     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
413     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
414     // specified uniform variable will not be changed.following opengl silently do nothing
415     return;
416   }
417
418   // Not caching these calls. Based on current analysis this is called very often
419   // but with different values (we're using this for MVP matrices)
420   // NOTE! we never want driver or GPU to transpose
421   LOG_GL( "UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
422   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix4fv( location, count, GL_FALSE, value ) );
423 }
424
425 void Program::SetUniformMatrix3fv( GLint location, GLsizei count, const GLfloat* value )
426 {
427   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
428
429   if( UNIFORM_UNKNOWN == location )
430   {
431     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
432     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
433     // specified uniform variable will not be changed.following opengl silently do nothing
434     return;
435   }
436
437
438   // Not caching these calls. Based on current analysis this is called very often
439   // but with different values (we're using this for MVP matrices)
440   // NOTE! we never want driver or GPU to transpose
441   LOG_GL( "UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
442   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix3fv( location, count, GL_FALSE, value ) );
443 }
444
445 void Program::GlContextCreated()
446 {
447 }
448
449 void Program::GlContextDestroyed()
450 {
451   mLinked = false;
452   mVertexShaderId = 0;
453   mFragmentShaderId = 0;
454   mProgramId = 0;
455
456   ResetAttribsUniformCache();
457 }
458
459 bool Program::ModifiesGeometry()
460 {
461   return mModifiesGeometry;
462 }
463
464 Program::Program( ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
465 : mCache( cache ),
466   mGlAbstraction( mCache.GetGlAbstraction() ),
467   mProjectionMatrix( NULL ),
468   mViewMatrix( NULL ),
469   mLinked( false ),
470   mVertexShaderId( 0 ),
471   mFragmentShaderId( 0 ),
472   mProgramId( 0 ),
473   mProgramData(shaderData),
474   mModifiesGeometry( modifiesGeometry )
475 {
476   // reserve space for standard attributes
477   mAttributeLocations.reserve( ATTRIB_TYPE_LAST );
478   for( int i=0; i<ATTRIB_TYPE_LAST; ++i )
479   {
480     RegisterCustomAttribute( gStdAttribs[i] );
481   }
482
483   // reserve space for standard uniforms
484   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
485   // reset built in uniform names in cache
486   for( int i = 0; i < UNIFORM_TYPE_LAST; ++i )
487   {
488     RegisterUniform( gStdUniforms[ i ] );
489   }
490   // reset values
491   ResetAttribsUniformCache();
492 }
493
494 Program::~Program()
495 {
496   Unload();
497 }
498
499 void Program::Load()
500 {
501   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
502   DALI_ASSERT_DEBUG( mProgramId == 0 && "mProgramId != 0, so about to leak a GL resource by overwriting it." );
503
504   LOG_GL( "CreateProgram()\n" );
505   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
506
507   GLint linked = GL_FALSE;
508
509   const bool binariesSupported = mCache.IsBinarySupported();
510
511   // if shader binaries are supported and ShaderData contains compiled bytecode?
512   if( binariesSupported && mProgramData->HasBinary() )
513   {
514     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
515
516     CHECK_GL( mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), mProgramData->GetBufferSize()) );
517
518     CHECK_GL( mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId) );
519
520     GLint success;
521     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_VALIDATE_STATUS, &success ) );
522
523     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
524
525     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
526
527     if( GL_FALSE == linked )
528     {
529       DALI_LOG_ERROR("Failed to load program binary \n");
530
531       GLint nLength;
532       CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength) );
533       if(nLength > 0)
534       {
535         Dali::Vector< char > szLog;
536         szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
537         CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() ) );
538         DALI_LOG_ERROR( "Program Link Error: %s\n", szLog.Begin() );
539       }
540     }
541     else
542     {
543       mLinked = true;
544       DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Reused binary.\n" );
545     }
546   }
547
548   // Fall back to compiling and linking the vertex and fragment sources
549   if( GL_FALSE == linked )
550   {
551     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
552     if( CompileShader( GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader() ) )
553     {
554       if( CompileShader( GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader() ) )
555       {
556         Link();
557
558         if( binariesSupported && mLinked )
559         {
560           GLint  binaryLength = 0;
561           GLenum binaryFormat;
562           DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Compiled and linked.\n\nVS:\n%s\nFS:\n%s\n", mProgramData->GetVertexShader(), mProgramData->GetFragmentShader() );
563
564           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
565           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
566           if( binaryLength > 0 )
567           {
568             // Allocate space for the bytecode in ShaderData
569             mProgramData->AllocateBuffer(binaryLength);
570             // Copy the bytecode to ShaderData
571             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
572             mCache.StoreBinary( mProgramData );
573             DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Saved binary.\n" );
574           }
575         }
576       }
577     }
578   }
579
580   // No longer needed
581   FreeShaders();
582 }
583
584 void Program::Unload()
585 {
586   FreeShaders();
587
588   if( this == mCache.GetCurrentProgram() )
589   {
590     CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(0) );
591
592     mCache.SetCurrentProgram( NULL );
593   }
594
595   if (mProgramId)
596   {
597     LOG_GL( "DeleteProgram(%d)\n", mProgramId );
598     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteProgram( mProgramId ) );
599     mProgramId = 0;
600   }
601
602   mLinked = false;
603
604 }
605
606 bool Program::CompileShader( GLenum shaderType, GLuint& shaderId, const char* src )
607 {
608   if (!shaderId)
609   {
610     LOG_GL( "CreateShader(%d)\n", shaderType );
611     shaderId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateShader( shaderType ) );
612     LOG_GL( "AttachShader(%d,%d)\n", mProgramId, shaderId );
613     CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( mProgramId, shaderId ) );
614   }
615
616   LOG_GL( "ShaderSource(%d)\n", shaderId );
617   CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, NULL ) );
618
619   LOG_GL( "CompileShader(%d)\n", shaderId );
620   CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shaderId ) );
621
622   GLint compiled;
623   LOG_GL( "GetShaderiv(%d)\n", shaderId );
624   CHECK_GL( mGlAbstraction, mGlAbstraction.GetShaderiv( shaderId, GL_COMPILE_STATUS, &compiled ) );
625
626   if (compiled == GL_FALSE)
627   {
628     DALI_LOG_ERROR("Failed to compile shader\n");
629     LogWithLineNumbers(src);
630
631     GLint nLength;
632     mGlAbstraction.GetShaderiv( shaderId, GL_INFO_LOG_LENGTH, &nLength);
633     if(nLength > 0)
634     {
635       Dali::Vector< char > szLog;
636       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
637       mGlAbstraction.GetShaderInfoLog( shaderId, nLength, &nLength, szLog.Begin() );
638       DALI_LOG_ERROR( "Shader Compiler Error: %s\n", szLog.Begin() );
639     }
640
641     DALI_ASSERT_ALWAYS( 0 && "Shader compilation failure" );
642   }
643
644   return compiled != 0;
645 }
646
647 void Program::Link()
648 {
649   LOG_GL( "LinkProgram(%d)\n", mProgramId );
650   CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( mProgramId ) );
651
652   GLint linked;
653   LOG_GL( "GetProgramiv(%d)\n", mProgramId );
654   CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
655
656   if (linked == GL_FALSE)
657   {
658     DALI_LOG_ERROR("Shader failed to link \n");
659
660     GLint nLength;
661     mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength);
662     if(nLength > 0)
663     {
664       Dali::Vector< char > szLog;
665       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
666       mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() );
667       DALI_LOG_ERROR( "Shader Link Error: %s\n", szLog.Begin() );
668     }
669
670     DALI_ASSERT_ALWAYS( 0 && "Shader linking failure" );
671   }
672
673   mLinked = linked != GL_FALSE;
674 }
675
676 void Program::FreeShaders()
677 {
678   if (mVertexShaderId)
679   {
680     LOG_GL( "DeleteShader(%d)\n", mVertexShaderId );
681     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mVertexShaderId ) );
682     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mVertexShaderId ) );
683     mVertexShaderId = 0;
684   }
685
686   if (mFragmentShaderId)
687   {
688     LOG_GL( "DeleteShader(%d)\n", mFragmentShaderId );
689     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mFragmentShaderId ) );
690     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mFragmentShaderId ) );
691     mFragmentShaderId = 0;
692   }
693 }
694
695 void Program::ResetAttribsUniformCache()
696 {
697   // reset attribute locations
698   for( unsigned i = 0; i < mAttributeLocations.size() ; ++i )
699   {
700     mAttributeLocations[ i ].second = ATTRIB_UNKNOWN;
701   }
702
703   // reset all gl uniform locations
704   for( unsigned int i = 0; i < mUniformLocations.size(); ++i )
705   {
706     // reset gl program locations and names
707     mUniformLocations[ i ].second = UNIFORM_NOT_QUERIED;
708   }
709
710   // reset uniform caches
711   mSizeUniformCache.x = mSizeUniformCache.y = mSizeUniformCache.z = 0.f;
712
713   for( int i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i )
714   {
715     // GL initializes uniforms to 0
716     mUniformCacheInt[ i ] = 0;
717     mUniformCacheFloat[ i ] = 0.0f;
718     mUniformCacheFloat4[ i ][ 0 ] = 0.0f;
719     mUniformCacheFloat4[ i ][ 1 ] = 0.0f;
720     mUniformCacheFloat4[ i ][ 2 ] = 0.0f;
721     mUniformCacheFloat4[ i ][ 3 ] = 0.0f;
722   }
723 }
724
725 } // namespace Internal
726
727 } // namespace Dali