Merge branch 'devel/master' into devel/new_mesh
[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   "uSize"                 // UNIFORM_SIZE
107 };
108
109 }  // <unnamed> namespace
110
111 // IMPLEMENTATION
112
113 Program* Program::New( ProgramCache& cache, Integration::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::SetUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
337 {
338   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
339
340   if( UNIFORM_UNKNOWN == location )
341   {
342     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
343     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
344     // specified uniform variable will not be changed.following opengl silently do nothing
345     return;
346   }
347
348   // Not caching these as based on current analysis this is not called that often by our shaders
349   LOG_GL( "Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2 );
350   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform3f( location, value0, value1, value2 ) );
351 }
352
353 void Program::SetUniform4f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3 )
354 {
355   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
356
357   if( UNIFORM_UNKNOWN == location )
358   {
359     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
360     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
361     // specified uniform variable will not be changed.following opengl silently do nothing
362     return;
363   }
364
365   // check if uniform location fits the cache
366   if( location >= MAX_UNIFORM_CACHE_SIZE )
367   {
368     // not cached, make the gl call
369     LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
370     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
371   }
372   else
373   {
374     // check if the same value has already been set, reset if any component is different
375     // checking index 3 first because we're often animating alpha (rgba)
376     if( ( fabsf(value3 - mUniformCacheFloat4[ location ][ 3 ]) >= Math::MACHINE_EPSILON_1 )||
377         ( fabsf(value0 - mUniformCacheFloat4[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
378         ( fabsf(value1 - mUniformCacheFloat4[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 )||
379         ( fabsf(value2 - mUniformCacheFloat4[ location ][ 2 ]) >= Math::MACHINE_EPSILON_1 ) )
380     {
381       // 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       // update cache
385       mUniformCacheFloat4[ location ][ 0 ] = value0;
386       mUniformCacheFloat4[ location ][ 1 ] = value1;
387       mUniformCacheFloat4[ location ][ 2 ] = value2;
388       mUniformCacheFloat4[ location ][ 3 ] = value3;
389     }
390   }
391 }
392
393 void Program::SetUniformMatrix4fv( 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   // Not caching these calls. Based on current analysis this is called very often
406   // but with different values (we're using this for MVP matrices)
407   // NOTE! we never want driver or GPU to transpose
408   LOG_GL( "UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
409   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix4fv( location, count, GL_FALSE, value ) );
410 }
411
412 void Program::SetUniformMatrix3fv( GLint location, GLsizei count, const GLfloat* value )
413 {
414   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
415
416   if( UNIFORM_UNKNOWN == location )
417   {
418     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
419     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
420     // specified uniform variable will not be changed.following opengl silently do nothing
421     return;
422   }
423
424
425   // Not caching these calls. Based on current analysis this is called very often
426   // but with different values (we're using this for MVP matrices)
427   // NOTE! we never want driver or GPU to transpose
428   LOG_GL( "UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
429   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix3fv( location, count, GL_FALSE, value ) );
430 }
431
432 void Program::GlContextCreated()
433 {
434 }
435
436 void Program::GlContextDestroyed()
437 {
438   mLinked = false;
439   mVertexShaderId = 0;
440   mFragmentShaderId = 0;
441   mProgramId = 0;
442
443   ResetAttribsUniformCache();
444 }
445
446 bool Program::ModifiesGeometry()
447 {
448   return mModifiesGeometry;
449 }
450
451 Program::Program( ProgramCache& cache, Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
452 : mCache( cache ),
453   mGlAbstraction( mCache.GetGlAbstraction() ),
454   mProjectionMatrix( NULL ),
455   mViewMatrix( NULL ),
456   mLinked( false ),
457   mVertexShaderId( 0 ),
458   mFragmentShaderId( 0 ),
459   mProgramId( 0 ),
460   mProgramData(shaderData),
461   mModifiesGeometry( modifiesGeometry )
462 {
463   // reserve space for standard attributes
464   mAttributeLocations.reserve( ATTRIB_TYPE_LAST );
465   for( int i=0; i<ATTRIB_TYPE_LAST; ++i )
466   {
467     RegisterCustomAttribute( gStdAttribs[i] );
468   }
469
470   // reserve space for standard uniforms
471   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
472   // reset built in uniform names in cache
473   for( int i = 0; i < UNIFORM_TYPE_LAST; ++i )
474   {
475     RegisterUniform( gStdUniforms[ i ] );
476   }
477   // reset values
478   ResetAttribsUniformCache();
479 }
480
481 Program::~Program()
482 {
483   Unload();
484 }
485
486 void Program::Load()
487 {
488   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
489
490   LOG_GL( "CreateProgram()\n" );
491   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
492
493   GLint linked = GL_FALSE;
494
495   const bool binariesSupported = mCache.IsBinarySupported();
496
497   // if shader binaries are supported and ShaderData contains compiled bytecode?
498   if( binariesSupported && mProgramData->HasBinary() )
499   {
500     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
501
502     CHECK_GL( mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), mProgramData->GetBufferSize()) );
503
504     CHECK_GL( mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId) );
505
506     GLint success;
507     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_VALIDATE_STATUS, &success ) );
508
509     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
510
511     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
512
513     if( GL_FALSE == linked )
514     {
515       DALI_LOG_ERROR("Failed to load program binary \n");
516
517       GLint nLength;
518       CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength) );
519       if(nLength > 0)
520       {
521         Dali::Vector< char > szLog;
522         szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
523         CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() ) );
524         DALI_LOG_ERROR( "Program Link Error: %s\n", szLog.Begin() );
525       }
526     }
527     else
528     {
529       mLinked = true;
530     }
531   }
532
533   // Fall back to compiling and linking the vertex and fragment sources
534   if( GL_FALSE == linked )
535   {
536     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
537     if( CompileShader( GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader() ) )
538     {
539       if( CompileShader( GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader() ) )
540       {
541         Link();
542
543         if( binariesSupported && mLinked )
544         {
545           GLint  binaryLength = 0;
546           GLenum binaryFormat;
547
548           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
549           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
550           if( binaryLength > 0 )
551           {
552             // Allocate space for the bytecode in ShaderData
553             mProgramData->AllocateBuffer(binaryLength);
554             // Copy the bytecode to ShaderData
555             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
556             mCache.StoreBinary( mProgramData );
557           }
558         }
559       }
560     }
561   }
562
563   // No longer needed
564   FreeShaders();
565 }
566
567 void Program::Unload()
568 {
569   FreeShaders();
570
571   if( this == mCache.GetCurrentProgram() )
572   {
573     CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(0) );
574
575     mCache.SetCurrentProgram( NULL );
576   }
577
578   if (mProgramId)
579   {
580     LOG_GL( "DeleteProgram(%d)\n", mProgramId );
581     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteProgram( mProgramId ) );
582     mProgramId = 0;
583   }
584
585   mLinked = false;
586
587 }
588
589 bool Program::CompileShader( GLenum shaderType, GLuint& shaderId, const char* src )
590 {
591   if (!shaderId)
592   {
593     LOG_GL( "CreateShader(%d)\n", shaderType );
594     shaderId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateShader( shaderType ) );
595     LOG_GL( "AttachShader(%d,%d)\n", mProgramId, shaderId );
596     CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( mProgramId, shaderId ) );
597   }
598
599   LOG_GL( "ShaderSource(%d)\n", shaderId );
600   CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, NULL ) );
601
602   LOG_GL( "CompileShader(%d)\n", shaderId );
603   CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shaderId ) );
604
605   GLint compiled;
606   LOG_GL( "GetShaderiv(%d)\n", shaderId );
607   CHECK_GL( mGlAbstraction, mGlAbstraction.GetShaderiv( shaderId, GL_COMPILE_STATUS, &compiled ) );
608
609   if (compiled == GL_FALSE)
610   {
611     DALI_LOG_ERROR("Failed to compile shader\n");
612     LogWithLineNumbers(src);
613
614     GLint nLength;
615     mGlAbstraction.GetShaderiv( shaderId, GL_INFO_LOG_LENGTH, &nLength);
616     if(nLength > 0)
617     {
618       Dali::Vector< char > szLog;
619       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
620       mGlAbstraction.GetShaderInfoLog( shaderId, nLength, &nLength, szLog.Begin() );
621       DALI_LOG_ERROR( "Shader Compiler Error: %s\n", szLog.Begin() );
622     }
623
624     DALI_ASSERT_ALWAYS( 0 && "Shader compilation failure" );
625   }
626
627   return compiled != 0;
628 }
629
630 void Program::Link()
631 {
632   LOG_GL( "LinkProgram(%d)\n", mProgramId );
633   CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( mProgramId ) );
634
635   GLint linked;
636   LOG_GL( "GetProgramiv(%d)\n", mProgramId );
637   CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
638
639   if (linked == GL_FALSE)
640   {
641     DALI_LOG_ERROR("Shader failed to link \n");
642
643     GLint nLength;
644     mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength);
645     if(nLength > 0)
646     {
647       Dali::Vector< char > szLog;
648       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
649       mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() );
650       DALI_LOG_ERROR( "Shader Link Error: %s\n", szLog.Begin() );
651     }
652
653     DALI_ASSERT_ALWAYS( 0 && "Shader linking failure" );
654   }
655
656   mLinked = linked != GL_FALSE;
657 }
658
659 void Program::FreeShaders()
660 {
661   if (mVertexShaderId)
662   {
663     LOG_GL( "DeleteShader(%d)\n", mVertexShaderId );
664     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mVertexShaderId ) );
665     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mVertexShaderId ) );
666     mVertexShaderId = 0;
667   }
668
669   if (mFragmentShaderId)
670   {
671     LOG_GL( "DeleteShader(%d)\n", mFragmentShaderId );
672     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mFragmentShaderId ) );
673     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mFragmentShaderId ) );
674     mFragmentShaderId = 0;
675   }
676 }
677
678 void Program::ResetAttribsUniformCache()
679 {
680   // reset attribute locations
681   for( unsigned i = 0; i < mAttributeLocations.size() ; ++i )
682   {
683     mAttributeLocations[ i ].second = ATTRIB_UNKNOWN;
684   }
685
686   // reset all gl uniform locations
687   for( unsigned int i = 0; i < mUniformLocations.size(); ++i )
688   {
689     // reset gl program locations and names
690     mUniformLocations[ i ].second = UNIFORM_NOT_QUERIED;
691   }
692
693   // reset uniform cache
694   for( int i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i )
695   {
696     // GL initializes uniforms to 0
697     mUniformCacheInt[ i ] = 0;
698     mUniformCacheFloat[ i ] = 0.0f;
699     mUniformCacheFloat4[ i ][ 0 ] = 0.0f;
700     mUniformCacheFloat4[ i ][ 1 ] = 0.0f;
701     mUniformCacheFloat4[ i ][ 2 ] = 0.0f;
702     mUniformCacheFloat4[ i ][ 3 ] = 0.0f;
703   }
704 }
705
706 } // namespace Internal
707
708 } // namespace Dali