Merge remote-tracking branch 'origin/tizen' into new_text
[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/integration-api/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 };
107
108 }  // <unnamed> namespace
109
110 // IMPLEMENTATION
111
112 Program* Program::New( ProgramCache& cache, Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
113 {
114   size_t shaderHash = shaderData->GetHashValue();
115   Program* program = cache.GetProgram( shaderHash );
116
117   if( NULL == program )
118   {
119     // program not found so create it
120     program = new Program( cache, shaderData, modifiesGeometry );
121
122     // we want to lazy load programs so dont do a Load yet, it gets done in Use()
123
124     cache.AddProgram( shaderHash, program );
125   }
126
127   return program;
128 }
129
130 void Program::Use()
131 {
132   if ( !mLinked )
133   {
134     Load();
135   }
136
137   if ( mLinked )
138   {
139     if ( this != mCache.GetCurrentProgram() )
140     {
141       LOG_GL( "UseProgram(%d)\n", mProgramId );
142       CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(mProgramId) );
143       INCREASE_COUNTER(PerformanceMonitor::SHADER_STATE_CHANGES);
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   if( mAttribLocations[ type ] == ATTRIB_UNKNOWN )
160   {
161     GLint loc = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, gStdAttribs[type] ) );
162     mAttribLocations[ type ] = loc;
163     LOG_GL( "GetAttribLocation(program=%d,%s) = %d\n", mProgramId, gStdAttribs[type], mAttribLocations[type] );
164   }
165
166   return mAttribLocations[type];
167 }
168
169 unsigned int Program::RegisterUniform( const std::string& name )
170 {
171   unsigned int index = 0;
172   // find the value from cache
173   for( ;index < mUniformLocations.size(); ++index )
174   {
175     if( mUniformLocations[ index ].first == name )
176     {
177       // name found so return index
178       return index;
179     }
180   }
181   // if we get here, index is one past end so push back the new name
182   mUniformLocations.push_back( std::make_pair( name, UNIFORM_NOT_QUERIED ) );
183   return index;
184 }
185
186 GLint Program::GetUniformLocation( unsigned int uniformIndex )
187 {
188   // debug check that index is within name cache
189   DALI_ASSERT_DEBUG( mUniformLocations.size() > uniformIndex );
190
191   // check if we have already queried the location of the uniform
192   GLint location = mUniformLocations[ uniformIndex ].second;
193
194   if( location == UNIFORM_NOT_QUERIED )
195   {
196     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.c_str() ) );
197
198     mUniformLocations[ uniformIndex ].second = location;
199     LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.c_str(), mUniformLocations[ uniformIndex ].second );
200   }
201
202   return location;
203 }
204
205 void Program::SetUniform1i( GLint location, GLint value0 )
206 {
207   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
208
209   if( UNIFORM_UNKNOWN == location )
210   {
211     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
212     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
213     // specified uniform variable will not be changed.following opengl silently do nothing
214     return;
215   }
216
217   // check if uniform location fits the cache
218   if( location >= MAX_UNIFORM_CACHE_SIZE )
219   {
220     // not cached, make the gl call
221     LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
222     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
223   }
224   else
225   {
226     // check if the value is different from what's already been set
227     if( value0 != mUniformCacheInt[ location ] )
228     {
229       // make the gl call
230       LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
231       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
232       // update cache
233       mUniformCacheInt[ location ] = value0;
234     }
235   }
236 }
237
238 void Program::SetUniform4i( GLint location, GLint value0, GLint value1, GLint value2, GLint value3 )
239 {
240   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
241
242   if( UNIFORM_UNKNOWN == location )
243   {
244     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
245     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
246     // specified uniform variable will not be changed.following opengl silently do nothing
247     return;
248   }
249
250   // Not caching these as based on current analysis this is not called that often by our shaders
251   LOG_GL( "Uniform4i(%d,%d,%d,%d,%d)\n", location, value0, value1, value2, value3 );
252   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4i( location, value0, value1, value2, value3 ) );
253 }
254
255 void Program::SetUniform1f( GLint location, GLfloat value0 )
256 {
257   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
258
259   if( UNIFORM_UNKNOWN == location )
260   {
261     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
262     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
263     // specified uniform variable will not be changed.following opengl silently do nothing
264     return;
265   }
266
267   // check if uniform location fits the cache
268   if( location >= MAX_UNIFORM_CACHE_SIZE )
269   {
270     // not cached, make the gl call
271     LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
272     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
273   }
274   else
275   {
276     // check if the same value has already been set, reset if it is different
277     if( ( fabsf(value0 - mUniformCacheFloat[ location ]) >= Math::MACHINE_EPSILON_1 ) )
278     {
279       // make the gl call
280       LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
281       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
282
283       // update cache
284       mUniformCacheFloat[ location ] = value0;
285     }
286   }
287 }
288
289 void Program::SetUniform2f( GLint location, GLfloat value0, GLfloat value1 )
290 {
291   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
292
293   if( UNIFORM_UNKNOWN == location )
294   {
295     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
296     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
297     // specified uniform variable will not be changed.following opengl silently do nothing
298     return;
299   }
300
301   // Not caching these as based on current analysis this is not called that often by our shaders
302   LOG_GL( "Uniform2f(%d,%f,%f)\n", location, value0, value1 );
303   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform2f( location, value0, value1 ) );
304 }
305
306 void Program::SetUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
307 {
308   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
309
310   if( UNIFORM_UNKNOWN == location )
311   {
312     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
313     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
314     // specified uniform variable will not be changed.following opengl silently do nothing
315     return;
316   }
317
318   // Not caching these as based on current analysis this is not called that often by our shaders
319   LOG_GL( "Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2 );
320   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform3f( location, value0, value1, value2 ) );
321 }
322
323 void Program::SetUniform4f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3 )
324 {
325   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
326
327   if( UNIFORM_UNKNOWN == location )
328   {
329     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
330     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
331     // specified uniform variable will not be changed.following opengl silently do nothing
332     return;
333   }
334
335   // check if uniform location fits the cache
336   if( location >= MAX_UNIFORM_CACHE_SIZE )
337   {
338     // not cached, make the gl call
339     LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
340     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
341   }
342   else
343   {
344     // check if the same value has already been set, reset if any component is different
345     // checking index 3 first because we're often animating alpha (rgba)
346     if( ( fabsf(value3 - mUniformCacheFloat4[ location ][ 3 ]) >= Math::MACHINE_EPSILON_1 )||
347         ( fabsf(value0 - mUniformCacheFloat4[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
348         ( fabsf(value1 - mUniformCacheFloat4[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 )||
349         ( fabsf(value2 - mUniformCacheFloat4[ location ][ 2 ]) >= Math::MACHINE_EPSILON_1 ) )
350     {
351       // make the gl call
352       LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
353       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
354       // update cache
355       mUniformCacheFloat4[ location ][ 0 ] = value0;
356       mUniformCacheFloat4[ location ][ 1 ] = value1;
357       mUniformCacheFloat4[ location ][ 2 ] = value2;
358       mUniformCacheFloat4[ location ][ 3 ] = value3;
359     }
360   }
361 }
362
363 void Program::SetUniformMatrix4fv( GLint location, GLsizei count, const GLfloat* value )
364 {
365   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
366
367   if( UNIFORM_UNKNOWN == location )
368   {
369     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
370     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
371     // specified uniform variable will not be changed.following opengl silently do nothing
372     return;
373   }
374
375   // Not caching these calls. Based on current analysis this is called very often
376   // but with different values (we're using this for MVP matrices)
377   // NOTE! we never want driver or GPU to transpose
378   LOG_GL( "UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
379   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix4fv( location, count, GL_FALSE, value ) );
380 }
381
382 void Program::SetUniformMatrix3fv( GLint location, GLsizei count, const GLfloat* value )
383 {
384   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
385
386   if( UNIFORM_UNKNOWN == location )
387   {
388     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
389     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
390     // specified uniform variable will not be changed.following opengl silently do nothing
391     return;
392   }
393
394
395   // Not caching these calls. Based on current analysis this is called very often
396   // but with different values (we're using this for MVP matrices)
397   // NOTE! we never want driver or GPU to transpose
398   LOG_GL( "UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
399   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix3fv( location, count, GL_FALSE, value ) );
400 }
401
402 void Program::GlContextCreated()
403 {
404 }
405
406 void Program::GlContextDestroyed()
407 {
408   mLinked = false;
409   mVertexShaderId = 0;
410   mFragmentShaderId = 0;
411   mProgramId = 0;
412
413   ResetAttribsUniformCache();
414 }
415
416 bool Program::ModifiesGeometry()
417 {
418   return mModifiesGeometry;
419 }
420
421 Program::Program( ProgramCache& cache, Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
422 : mCache( cache ),
423   mGlAbstraction( mCache.GetGlAbstraction() ),
424   mProjectionMatrix( NULL ),
425   mViewMatrix( NULL ),
426   mLinked( false ),
427   mVertexShaderId( 0 ),
428   mFragmentShaderId( 0 ),
429   mProgramId( 0 ),
430   mProgramData(shaderData),
431   mModifiesGeometry( modifiesGeometry )
432 {
433   // reserve space for standard uniforms
434   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
435   // reset built in uniform names in cache
436   for( int i = 0; i < UNIFORM_TYPE_LAST; ++i )
437   {
438     RegisterUniform( gStdUniforms[ i ] );
439   }
440   // reset values
441   ResetAttribsUniformCache();
442 }
443
444 Program::~Program()
445 {
446   Unload();
447 }
448
449 void Program::Load()
450 {
451   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
452
453   LOG_GL( "CreateProgram()\n" );
454   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
455
456   GLint linked = GL_FALSE;
457
458   const bool binariesSupported = mCache.IsBinarySupported();
459
460   // if shader binaries are supported and ShaderData contains compiled bytecode?
461   if( binariesSupported && mProgramData->HasBinary() )
462   {
463     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
464
465     CHECK_GL( mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), mProgramData->GetBufferSize()) );
466
467     CHECK_GL( mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId) );
468
469     GLint success;
470     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_VALIDATE_STATUS, &success ) );
471
472     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
473
474     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
475
476     if( GL_FALSE == linked )
477     {
478       DALI_LOG_ERROR("Failed to load program binary \n");
479
480       char* szLog = NULL;
481       GLint nLength;
482       CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength) );
483       if(nLength > 0)
484       {
485         szLog = new char[ nLength ];
486         CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog ) );
487         DALI_LOG_ERROR( "Program Link Error: %s\n", szLog );
488
489         delete [] szLog;
490       }
491     }
492     else
493     {
494       mLinked = true;
495     }
496   }
497
498   // Fall back to compiling and linking the vertex and fragment sources
499   if( GL_FALSE == linked )
500   {
501     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
502     if( CompileShader( GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader() ) )
503     {
504       if( CompileShader( GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader() ) )
505       {
506         Link();
507
508         if( binariesSupported && mLinked )
509         {
510           GLint  binaryLength = 0;
511           GLenum binaryFormat;
512
513           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
514           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
515           if( binaryLength > 0 )
516           {
517             // Allocate space for the bytecode in ShaderData
518             mProgramData->AllocateBuffer(binaryLength);
519             // Copy the bytecode to ShaderData
520             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
521             mCache.StoreBinary( mProgramData );
522           }
523         }
524       }
525     }
526   }
527
528   // No longer needed
529   FreeShaders();
530 }
531
532 void Program::Unload()
533 {
534   FreeShaders();
535
536   if( this == mCache.GetCurrentProgram() )
537   {
538     CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(0) );
539
540     mCache.SetCurrentProgram( NULL );
541   }
542
543   if (mProgramId)
544   {
545     LOG_GL( "DeleteProgram(%d)\n", mProgramId );
546     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteProgram( mProgramId ) );
547     mProgramId = 0;
548   }
549
550   mLinked = false;
551
552 }
553
554 bool Program::CompileShader( GLenum shaderType, GLuint& shaderId, const char* src )
555 {
556   if (!shaderId)
557   {
558     LOG_GL( "CreateShader(%d)\n", shaderType );
559     shaderId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateShader( shaderType ) );
560     LOG_GL( "AttachShader(%d,%d)\n", mProgramId, shaderId );
561     CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( mProgramId, shaderId ) );
562   }
563
564   LOG_GL( "ShaderSource(%d)\n", shaderId );
565   CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, NULL ) );
566
567   LOG_GL( "CompileShader(%d)\n", shaderId );
568   CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shaderId ) );
569
570   GLint compiled;
571   LOG_GL( "GetShaderiv(%d)\n", shaderId );
572   CHECK_GL( mGlAbstraction, mGlAbstraction.GetShaderiv( shaderId, GL_COMPILE_STATUS, &compiled ) );
573
574   if (compiled == GL_FALSE)
575   {
576     DALI_LOG_ERROR("Failed to compile shader\n");
577     LogWithLineNumbers(src);
578
579     GLint nLength;
580     mGlAbstraction.GetShaderiv( shaderId, GL_INFO_LOG_LENGTH, &nLength);
581     if(nLength > 0)
582     {
583       Dali::Vector< char > szLog;
584       szLog.Resize( nLength );
585       mGlAbstraction.GetShaderInfoLog( shaderId, nLength, &nLength, szLog.Begin() );
586       DALI_LOG_ERROR( "Shader Compiler Error: %s\n", szLog.Begin() );
587     }
588
589     DALI_ASSERT_ALWAYS( 0 && "Shader compilation failure" );
590   }
591
592   return compiled != 0;
593 }
594
595 void Program::Link()
596 {
597   LOG_GL( "LinkProgram(%d)\n", mProgramId );
598   CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( mProgramId ) );
599
600   GLint linked;
601   LOG_GL( "GetProgramiv(%d)\n", mProgramId );
602   CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
603
604   if (linked == GL_FALSE)
605   {
606     DALI_LOG_ERROR("Shader failed to link \n");
607
608     GLint nLength;
609     mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength);
610     if(nLength > 0)
611     {
612       Dali::Vector< char > szLog;
613       szLog.Resize( nLength );
614       mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() );
615       DALI_LOG_ERROR( "Shader Link Error: %s\n", szLog.Begin() );
616     }
617
618     DALI_ASSERT_ALWAYS( 0 && "Shader linking failure" );
619   }
620
621   mLinked = linked != GL_FALSE;
622 }
623
624 void Program::FreeShaders()
625 {
626   if (mVertexShaderId)
627   {
628     LOG_GL( "DeleteShader(%d)\n", mVertexShaderId );
629     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mVertexShaderId ) );
630     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mVertexShaderId ) );
631     mVertexShaderId = 0;
632   }
633
634   if (mFragmentShaderId)
635   {
636     LOG_GL( "DeleteShader(%d)\n", mFragmentShaderId );
637     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mFragmentShaderId ) );
638     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mFragmentShaderId ) );
639     mFragmentShaderId = 0;
640   }
641 }
642
643 void Program::ResetAttribsUniformCache()
644 {
645   // reset attribute locations
646   for( unsigned i = 0; i < ATTRIB_TYPE_LAST; ++i )
647   {
648     mAttribLocations[ i ] = ATTRIB_UNKNOWN;
649   }
650
651   // reset all gl uniform locations
652   for( unsigned int i = 0; i < mUniformLocations.size(); ++i )
653   {
654     // reset gl program locations and names
655     mUniformLocations[ i ].second = UNIFORM_NOT_QUERIED;
656   }
657
658   // reset uniform cache
659   for( int i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i )
660   {
661     // GL initializes uniforms to 0
662     mUniformCacheInt[ i ] = 0;
663     mUniformCacheFloat[ i ] = 0.0f;
664     mUniformCacheFloat4[ i ][ 0 ] = 0.0f;
665     mUniformCacheFloat4[ i ][ 1 ] = 0.0f;
666     mUniformCacheFloat4[ i ][ 2 ] = 0.0f;
667     mUniformCacheFloat4[ i ][ 3 ] = 0.0f;
668   }
669 }
670
671 } // namespace Internal
672
673 } // namespace Dali