Merge branch 'devel/master' into tizen
[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 #include <cstring>
24
25 // INTERNAL INCLUDES
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/common/dali-vector.h>
28 #include <dali/public-api/common/constants.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/internal/common/shader-data.h>
31 #include <dali/integration-api/gl-defines.h>
32 #include <dali/internal/render/common/performance-monitor.h>
33 #include <dali/internal/render/shaders/program-cache.h>
34 #include <dali/internal/render/gl-resources/gl-call-debug.h>
35
36 namespace
37 {
38 void LogWithLineNumbers( const char * source )
39 {
40   unsigned int lineNumber = 0u;
41   const char *prev = source;
42   const char *ptr = prev;
43
44   while( true )
45   {
46     if(lineNumber > 200u)
47     {
48       break;
49     }
50     // seek the next end of line or end of text
51     while( *ptr!='\n' && *ptr != '\0' )
52     {
53       ++ptr;
54     }
55
56     std::string line( prev, ptr-prev );
57     Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, "%4d %s\n", lineNumber, line.c_str());
58
59     if( *ptr == '\0' )
60     {
61       break;
62     }
63     prev = ++ptr;
64     ++lineNumber;
65   }
66 }
67
68 } //namespace
69
70 namespace Dali
71 {
72
73 namespace Internal
74 {
75
76 // LOCAL STUFF
77 namespace
78 {
79
80 const char* gStdAttribs[ Program::ATTRIB_TYPE_LAST ] =
81 {
82   "aPosition",    // ATTRIB_POSITION
83   "aTexCoord",    // ATTRIB_TEXCOORD
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   "sTexture",             // UNIFORM_SAMPLER
96   "sTextureRect",         // UNIFORM_SAMPLER_RECT
97   "sEffect",              // UNIFORM_EFFECT_SAMPLER
98   "uSize"                 // UNIFORM_SIZE
99 };
100
101 }  // <unnamed> namespace
102
103 // IMPLEMENTATION
104
105 Program* Program::New( ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
106 {
107   size_t shaderHash = shaderData->GetHashValue();
108   Program* program = cache.GetProgram( shaderHash );
109
110   if( NULL == program )
111   {
112     // program not found so create it
113     program = new Program( cache, shaderData, modifiesGeometry );
114
115     // we want to lazy load programs so dont do a Load yet, it gets done in Use()
116     cache.AddProgram( shaderHash, program );
117   }
118
119   return program;
120 }
121
122 void Program::Use()
123 {
124   if ( !mLinked )
125   {
126     Load();
127   }
128
129   if ( mLinked )
130   {
131     if ( this != mCache.GetCurrentProgram() )
132     {
133       LOG_GL( "UseProgram(%d)\n", mProgramId );
134       CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(mProgramId) );
135
136       mCache.SetCurrentProgram( this );
137     }
138   }
139 }
140
141 bool Program::IsUsed()
142 {
143   return ( this == mCache.GetCurrentProgram() );
144 }
145
146 GLint Program::GetAttribLocation( AttribType type )
147 {
148   DALI_ASSERT_DEBUG(type != ATTRIB_UNKNOWN);
149
150   return GetCustomAttributeLocation( type );
151 }
152
153 unsigned int Program::RegisterCustomAttribute( const std::string& name )
154 {
155   unsigned int index = 0;
156   // find the value from cache
157   for( ;index < mAttributeLocations.size(); ++index )
158   {
159     if( mAttributeLocations[ index ].first == name )
160     {
161       // name found so return index
162       return index;
163     }
164   }
165   // if we get here, index is one past end so push back the new name
166   mAttributeLocations.push_back( std::make_pair( name, ATTRIB_UNKNOWN ) );
167   return index;
168 }
169
170 GLint Program::GetCustomAttributeLocation( unsigned int attributeIndex )
171 {
172   // debug check that index is within name cache
173   DALI_ASSERT_DEBUG( mAttributeLocations.size() > attributeIndex );
174
175   // check if we have already queried the location of the attribute
176   GLint location = mAttributeLocations[ attributeIndex ].second;
177
178   if( location == ATTRIB_UNKNOWN )
179   {
180     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, mAttributeLocations[ attributeIndex ].first.c_str() ) );
181
182     mAttributeLocations[ attributeIndex ].second = location;
183     LOG_GL( "GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[ attributeIndex ].first.c_str(), mAttributeLocations[ attributeIndex ].second );
184   }
185
186   return location;
187 }
188
189
190 unsigned int Program::RegisterUniform( const std::string& name )
191 {
192   unsigned int index = 0;
193   // find the value from cache
194   for( ;index < mUniformLocations.size(); ++index )
195   {
196     if( mUniformLocations[ index ].first == name )
197     {
198       // name found so return index
199       return index;
200     }
201   }
202   // if we get here, index is one past end so push back the new name
203   mUniformLocations.push_back( std::make_pair( name, UNIFORM_NOT_QUERIED ) );
204   return index;
205 }
206
207 GLint Program::GetUniformLocation( unsigned int uniformIndex )
208 {
209   // debug check that index is within name cache
210   DALI_ASSERT_DEBUG( mUniformLocations.size() > uniformIndex );
211
212   // check if we have already queried the location of the uniform
213   GLint location = mUniformLocations[ uniformIndex ].second;
214
215   if( location == UNIFORM_NOT_QUERIED )
216   {
217     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.c_str() ) );
218
219     mUniformLocations[ uniformIndex ].second = location;
220     LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.c_str(), mUniformLocations[ uniformIndex ].second );
221   }
222
223   return location;
224 }
225
226 namespace
227 {
228 /**
229  * This struct is used to record the position of a uniform declaration
230  * within the fragment shader source code.
231  */
232 struct LocationPosition
233 {
234   GLint uniformLocation; ///< The location of the uniform (used as an identifier)
235   int position;          ///< the position of the uniform declaration
236   LocationPosition( GLint uniformLocation, int position )
237   : uniformLocation(uniformLocation), position(position)
238   {
239   }
240 };
241
242 bool sortByPosition( LocationPosition a, LocationPosition b )
243 {
244   return a.position < b.position;
245 }
246 }
247
248 void Program::GetActiveSamplerUniforms()
249 {
250   GLint numberOfActiveUniforms = -1;
251   GLint uniformMaxNameLength=-1;
252
253   mGlAbstraction.GetProgramiv( mProgramId, GL_ACTIVE_UNIFORMS, &numberOfActiveUniforms );
254   mGlAbstraction.GetProgramiv( mProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength );
255
256   std::vector<std::string> samplerNames;
257   char name[uniformMaxNameLength+1]; // Allow for null terminator
258   std::vector< LocationPosition >  samplerUniformLocations;
259
260   {
261     int nameLength = -1;
262     int number = -1;
263     GLenum type = GL_ZERO;
264
265     for( int i=0; i<numberOfActiveUniforms; ++i )
266     {
267       mGlAbstraction.GetActiveUniform( mProgramId, (GLuint)i, uniformMaxNameLength,
268                                        &nameLength, &number, &type, name );
269
270       if( type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE ) /// Is there a native sampler type?
271       {
272         GLuint location = mGlAbstraction.GetUniformLocation( mProgramId, name );
273         samplerNames.push_back(name);
274         samplerUniformLocations.push_back(LocationPosition(location, -1));
275       }
276     }
277   }
278
279   //Determine declaration order of each sampler
280   char* fragShader = strdup( mProgramData->GetFragmentShader() );
281   const char* token = strtok( fragShader, " ;\n");
282   int samplerPosition = 0;
283   while( token )
284   {
285     if( ( strncmp( token, "sampler2D", 9u ) == 0 ) || ( strncmp( token, "samplerCube", 11u ) == 0 ) )
286     {
287       bool found( false );
288       token = strtok( NULL, " ;\n");
289       for( size_t i=0; i<samplerUniformLocations.size(); ++i )
290       {
291         if( samplerUniformLocations[i].position == -1 &&
292             strncmp( token, samplerNames[i].c_str(), samplerNames[i].size() ) == 0 )
293         {
294           samplerUniformLocations[i].position = samplerPosition++;
295           found = true;
296           break;
297         }
298       }
299       if( !found )
300       {
301         DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token );
302       }
303     }
304     else
305     {
306       token = strtok( NULL, " ;\n");
307     }
308   }
309
310   free( fragShader );
311
312   // Re-order according to declaration order in the fragment source.
313   size_t samplerUniformCount = samplerUniformLocations.size();
314   if( samplerUniformCount > 1 )
315   {
316     std::sort( samplerUniformLocations.begin(), samplerUniformLocations.end(), sortByPosition);
317   }
318
319   mSamplerUniformLocations.resize( samplerUniformCount );
320   for( size_t i=0; i<samplerUniformCount; ++i )
321   {
322     mSamplerUniformLocations[i] = samplerUniformLocations[i].uniformLocation;
323   }
324 }
325
326 bool Program::GetSamplerUniformLocation( unsigned int index, GLint& location  )
327 {
328   bool result = false;
329   if( index < mSamplerUniformLocations.size() )
330   {
331     location = mSamplerUniformLocations[index];
332     result = true;
333   }
334   return result;
335 }
336
337 size_t Program::GetActiveSamplerCount() const
338 {
339   return mSamplerUniformLocations.size();
340 }
341
342 void Program::SetUniform1i( GLint location, GLint value0 )
343 {
344   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
345
346   if( UNIFORM_UNKNOWN == location )
347   {
348     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
349     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
350     // specified uniform variable will not be changed.following opengl silently do nothing
351     return;
352   }
353
354   // check if uniform location fits the cache
355   if( location >= MAX_UNIFORM_CACHE_SIZE )
356   {
357     // not cached, make the gl call
358     LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
359     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
360   }
361   else
362   {
363     // check if the value is different from what's already been set
364     if( value0 != mUniformCacheInt[ location ] )
365     {
366       // make the gl call
367       LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
368       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
369       // update cache
370       mUniformCacheInt[ location ] = value0;
371     }
372   }
373 }
374
375 void Program::SetUniform4i( GLint location, GLint value0, GLint value1, GLint value2, GLint value3 )
376 {
377   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
378
379   if( UNIFORM_UNKNOWN == location )
380   {
381     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
382     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
383     // specified uniform variable will not be changed.following opengl silently do nothing
384     return;
385   }
386
387   // Not caching these as based on current analysis this is not called that often by our shaders
388   LOG_GL( "Uniform4i(%d,%d,%d,%d,%d)\n", location, value0, value1, value2, value3 );
389   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4i( location, value0, value1, value2, value3 ) );
390 }
391
392 void Program::SetUniform1f( GLint location, GLfloat value0 )
393 {
394   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
395
396   if( UNIFORM_UNKNOWN == location )
397   {
398     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
399     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
400     // specified uniform variable will not be changed.following opengl silently do nothing
401     return;
402   }
403
404   // check if uniform location fits the cache
405   if( location >= MAX_UNIFORM_CACHE_SIZE )
406   {
407     // not cached, make the gl call
408     LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
409     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
410   }
411   else
412   {
413     // check if the same value has already been set, reset if it is different
414     if( ( fabsf(value0 - mUniformCacheFloat[ location ]) >= Math::MACHINE_EPSILON_1 ) )
415     {
416       // make the gl call
417       LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
418       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
419
420       // update cache
421       mUniformCacheFloat[ location ] = value0;
422     }
423   }
424 }
425
426 void Program::SetUniform2f( GLint location, GLfloat value0, GLfloat value1 )
427 {
428   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
429
430   if( UNIFORM_UNKNOWN == location )
431   {
432     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
433     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
434     // specified uniform variable will not be changed.following opengl silently do nothing
435     return;
436   }
437
438   // check if uniform location fits the cache
439   if( location >= MAX_UNIFORM_CACHE_SIZE )
440   {
441     // not cached, make the gl call
442     LOG_GL( "Uniform2f(%d,%f,%f)\n", location, value0, value1 );
443     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform2f( location, value0, value1 ) );
444   }
445   else
446   {
447     // check if the same value has already been set, reset if it is different
448     if( ( fabsf(value0 - mUniformCacheFloat2[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
449         ( fabsf(value1 - mUniformCacheFloat2[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 ) )
450     {
451       // make the gl call
452       LOG_GL( "Uniform2f(%d,%f,%f)\n", location, value0, value1 );
453       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform2f( location, value0, value1 ) );
454
455       // update cache
456       mUniformCacheFloat2[ location ][ 0 ] = value0;
457       mUniformCacheFloat2[ location ][ 1 ] = value1;
458     }
459   }
460 }
461
462 void Program::SetSizeUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
463 {
464   if( ( fabsf(value0 - mSizeUniformCache.x) >= Math::MACHINE_EPSILON_1 )||
465       ( fabsf(value1 - mSizeUniformCache.y) >= Math::MACHINE_EPSILON_1 )||
466       ( fabsf(value2 - mSizeUniformCache.z) >= Math::MACHINE_EPSILON_1 ) )
467   {
468     mSizeUniformCache.x = value0;
469     mSizeUniformCache.y = value1;
470     mSizeUniformCache.z = value2;
471     SetUniform3f( location, value0, value1, value2 );
472   }
473 }
474
475 void Program::SetUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
476 {
477   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
478
479   if( UNIFORM_UNKNOWN == location )
480   {
481     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
482     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
483     // specified uniform variable will not be changed.following opengl silently do nothing
484     return;
485   }
486
487   // Not caching these as based on current analysis this is not called that often by our shaders
488   LOG_GL( "Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2 );
489   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform3f( location, value0, value1, value2 ) );
490 }
491
492 void Program::SetUniform4f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3 )
493 {
494   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
495
496   if( UNIFORM_UNKNOWN == location )
497   {
498     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
499     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
500     // specified uniform variable will not be changed.following opengl silently do nothing
501     return;
502   }
503
504   // check if uniform location fits the cache
505   if( location >= MAX_UNIFORM_CACHE_SIZE )
506   {
507     // not cached, make the gl call
508     LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
509     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
510   }
511   else
512   {
513     // check if the same value has already been set, reset if any component is different
514     // checking index 3 first because we're often animating alpha (rgba)
515     if( ( fabsf(value3 - mUniformCacheFloat4[ location ][ 3 ]) >= Math::MACHINE_EPSILON_1 )||
516         ( fabsf(value0 - mUniformCacheFloat4[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
517         ( fabsf(value1 - mUniformCacheFloat4[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 )||
518         ( fabsf(value2 - mUniformCacheFloat4[ location ][ 2 ]) >= Math::MACHINE_EPSILON_1 ) )
519     {
520       // make the gl call
521       LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
522       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
523       // update cache
524       mUniformCacheFloat4[ location ][ 0 ] = value0;
525       mUniformCacheFloat4[ location ][ 1 ] = value1;
526       mUniformCacheFloat4[ location ][ 2 ] = value2;
527       mUniformCacheFloat4[ location ][ 3 ] = value3;
528     }
529   }
530 }
531
532 void Program::SetUniformMatrix4fv( GLint location, GLsizei count, const GLfloat* value )
533 {
534   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
535
536   if( UNIFORM_UNKNOWN == location )
537   {
538     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
539     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
540     // specified uniform variable will not be changed.following opengl silently do nothing
541     return;
542   }
543
544   // Not caching these calls. Based on current analysis this is called very often
545   // but with different values (we're using this for MVP matrices)
546   // NOTE! we never want driver or GPU to transpose
547   LOG_GL( "UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
548   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix4fv( location, count, GL_FALSE, value ) );
549 }
550
551 void Program::SetUniformMatrix3fv( GLint location, GLsizei count, const GLfloat* value )
552 {
553   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
554
555   if( UNIFORM_UNKNOWN == location )
556   {
557     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
558     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
559     // specified uniform variable will not be changed.following opengl silently do nothing
560     return;
561   }
562
563
564   // Not caching these calls. Based on current analysis this is called very often
565   // but with different values (we're using this for MVP matrices)
566   // NOTE! we never want driver or GPU to transpose
567   LOG_GL( "UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
568   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix3fv( location, count, GL_FALSE, value ) );
569 }
570
571 void Program::GlContextCreated()
572 {
573 }
574
575 void Program::GlContextDestroyed()
576 {
577   mLinked = false;
578   mVertexShaderId = 0;
579   mFragmentShaderId = 0;
580   mProgramId = 0;
581
582   ResetAttribsUniformCache();
583 }
584
585 bool Program::ModifiesGeometry()
586 {
587   return mModifiesGeometry;
588 }
589
590 Program::Program( ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
591 : mCache( cache ),
592   mGlAbstraction( mCache.GetGlAbstraction() ),
593   mProjectionMatrix( NULL ),
594   mViewMatrix( NULL ),
595   mLinked( false ),
596   mVertexShaderId( 0 ),
597   mFragmentShaderId( 0 ),
598   mProgramId( 0 ),
599   mProgramData(shaderData),
600   mModifiesGeometry( modifiesGeometry )
601 {
602   // reserve space for standard attributes
603   mAttributeLocations.reserve( ATTRIB_TYPE_LAST );
604   for( int i=0; i<ATTRIB_TYPE_LAST; ++i )
605   {
606     RegisterCustomAttribute( gStdAttribs[i] );
607   }
608
609   // reserve space for standard uniforms
610   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
611   // reset built in uniform names in cache
612   for( int i = 0; i < UNIFORM_TYPE_LAST; ++i )
613   {
614     RegisterUniform( gStdUniforms[ i ] );
615   }
616
617   // reset values
618   ResetAttribsUniformCache();
619 }
620
621 Program::~Program()
622 {
623   Unload();
624 }
625
626 void Program::Load()
627 {
628   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
629   DALI_ASSERT_DEBUG( mProgramId == 0 && "mProgramId != 0, so about to leak a GL resource by overwriting it." );
630
631   LOG_GL( "CreateProgram()\n" );
632   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
633
634   GLint linked = GL_FALSE;
635
636   const bool binariesSupported = mCache.IsBinarySupported();
637
638   // if shader binaries are supported and ShaderData contains compiled bytecode?
639   if( binariesSupported && mProgramData->HasBinary() )
640   {
641     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
642
643     CHECK_GL( mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), mProgramData->GetBufferSize()) );
644
645     CHECK_GL( mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId) );
646
647     GLint success;
648     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_VALIDATE_STATUS, &success ) );
649
650     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
651
652     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
653
654     if( GL_FALSE == linked )
655     {
656       DALI_LOG_ERROR("Failed to load program binary \n");
657
658       GLint nLength;
659       CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength) );
660       if(nLength > 0)
661       {
662         Dali::Vector< char > szLog;
663         szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
664         CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() ) );
665         DALI_LOG_ERROR( "Program Link Error: %s\n", szLog.Begin() );
666       }
667     }
668     else
669     {
670       mLinked = true;
671       DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Reused binary.\n" );
672     }
673   }
674
675   // Fall back to compiling and linking the vertex and fragment sources
676   if( GL_FALSE == linked )
677   {
678     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
679     if( CompileShader( GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader() ) )
680     {
681       if( CompileShader( GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader() ) )
682       {
683         Link();
684
685         if( binariesSupported && mLinked )
686         {
687           GLint  binaryLength = 0;
688           GLenum binaryFormat;
689           DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Compiled and linked.\n\nVS:\n%s\nFS:\n%s\n", mProgramData->GetVertexShader(), mProgramData->GetFragmentShader() );
690
691           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
692           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
693           if( binaryLength > 0 )
694           {
695             // Allocate space for the bytecode in ShaderData
696             mProgramData->AllocateBuffer(binaryLength);
697             // Copy the bytecode to ShaderData
698             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
699             mCache.StoreBinary( mProgramData );
700             DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Saved binary.\n" );
701           }
702         }
703       }
704     }
705   }
706
707   GetActiveSamplerUniforms();
708
709   // No longer needed
710   FreeShaders();
711 }
712
713 void Program::Unload()
714 {
715   FreeShaders();
716
717   if( this == mCache.GetCurrentProgram() )
718   {
719     CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(0) );
720
721     mCache.SetCurrentProgram( NULL );
722   }
723
724   if (mProgramId)
725   {
726     LOG_GL( "DeleteProgram(%d)\n", mProgramId );
727     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteProgram( mProgramId ) );
728     mProgramId = 0;
729   }
730
731   mLinked = false;
732
733 }
734
735 bool Program::CompileShader( GLenum shaderType, GLuint& shaderId, const char* src )
736 {
737   if (!shaderId)
738   {
739     LOG_GL( "CreateShader(%d)\n", shaderType );
740     shaderId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateShader( shaderType ) );
741     LOG_GL( "AttachShader(%d,%d)\n", mProgramId, shaderId );
742     CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( mProgramId, shaderId ) );
743   }
744
745   LOG_GL( "ShaderSource(%d)\n", shaderId );
746   CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, NULL ) );
747
748   LOG_GL( "CompileShader(%d)\n", shaderId );
749   CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shaderId ) );
750
751   GLint compiled;
752   LOG_GL( "GetShaderiv(%d)\n", shaderId );
753   CHECK_GL( mGlAbstraction, mGlAbstraction.GetShaderiv( shaderId, GL_COMPILE_STATUS, &compiled ) );
754
755   if (compiled == GL_FALSE)
756   {
757     DALI_LOG_ERROR("Failed to compile shader\n");
758     LogWithLineNumbers(src);
759
760     GLint nLength;
761     mGlAbstraction.GetShaderiv( shaderId, GL_INFO_LOG_LENGTH, &nLength);
762     if(nLength > 0)
763     {
764       Dali::Vector< char > szLog;
765       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
766       mGlAbstraction.GetShaderInfoLog( shaderId, nLength, &nLength, szLog.Begin() );
767       DALI_LOG_ERROR( "Shader Compiler Error: %s\n", szLog.Begin() );
768     }
769
770     DALI_ASSERT_ALWAYS( 0 && "Shader compilation failure" );
771   }
772
773   return compiled != 0;
774 }
775
776 void Program::Link()
777 {
778   LOG_GL( "LinkProgram(%d)\n", mProgramId );
779   CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( mProgramId ) );
780
781   GLint linked;
782   LOG_GL( "GetProgramiv(%d)\n", mProgramId );
783   CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
784
785   if (linked == GL_FALSE)
786   {
787     DALI_LOG_ERROR("Shader failed to link \n");
788
789     GLint nLength;
790     mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength);
791     if(nLength > 0)
792     {
793       Dali::Vector< char > szLog;
794       szLog.Reserve( nLength ); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
795       mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() );
796       DALI_LOG_ERROR( "Shader Link Error: %s\n", szLog.Begin() );
797     }
798
799     DALI_ASSERT_ALWAYS( 0 && "Shader linking failure" );
800   }
801
802   mLinked = linked != GL_FALSE;
803 }
804
805 void Program::FreeShaders()
806 {
807   if (mVertexShaderId)
808   {
809     LOG_GL( "DeleteShader(%d)\n", mVertexShaderId );
810     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mVertexShaderId ) );
811     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mVertexShaderId ) );
812     mVertexShaderId = 0;
813   }
814
815   if (mFragmentShaderId)
816   {
817     LOG_GL( "DeleteShader(%d)\n", mFragmentShaderId );
818     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mFragmentShaderId ) );
819     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mFragmentShaderId ) );
820     mFragmentShaderId = 0;
821   }
822 }
823
824 void Program::ResetAttribsUniformCache()
825 {
826   // reset attribute locations
827   for( unsigned i = 0; i < mAttributeLocations.size() ; ++i )
828   {
829     mAttributeLocations[ i ].second = ATTRIB_UNKNOWN;
830   }
831
832   // reset all gl uniform locations
833   for( unsigned int i = 0; i < mUniformLocations.size(); ++i )
834   {
835     // reset gl program locations and names
836     mUniformLocations[ i ].second = UNIFORM_NOT_QUERIED;
837   }
838
839   mSamplerUniformLocations.clear();
840
841   // reset uniform caches
842   mSizeUniformCache.x = mSizeUniformCache.y = mSizeUniformCache.z = 0.f;
843
844   for( int i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i )
845   {
846     // GL initializes uniforms to 0
847     mUniformCacheInt[ i ] = 0;
848     mUniformCacheFloat[ i ] = 0.0f;
849     mUniformCacheFloat2[ i ][ 0 ] = 0.0f;
850     mUniformCacheFloat2[ i ][ 1 ] = 0.0f;
851     mUniformCacheFloat4[ i ][ 0 ] = 0.0f;
852     mUniformCacheFloat4[ i ][ 1 ] = 0.0f;
853     mUniformCacheFloat4[ i ][ 2 ] = 0.0f;
854     mUniformCacheFloat4[ i ][ 3 ] = 0.0f;
855   }
856 }
857
858 } // namespace Internal
859
860 } // namespace Dali