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