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