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