73b2ef549d4c3a6db4471d42aca416c1ef6066fb
[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   "uTextColor",           // UNIFORM_TEXT_COLOR
107   "uSmoothing",           // UNIFORM_SMOOTHING
108   "uOutline",             // UNIFORM_OUTLINE
109   "uOutlineColor",        // UNIFORM_OUTLINE_COLOR
110   "uGlow",                // UNIFORM_GLOW
111   "uGlowColor",           // UNIFORM_GLOW_COLOR
112   "uShadow",              // UNIFORM_SHADOW
113   "uShadowColor",         // UNIFORM_SHADOW_COLOR
114   "uShadowSmoothing",     // UNIFORM_SHADOW_SMOOTHING
115   "uGradientColor",       // UNIFORM_GRADIENT_COLOR
116   "uGradientLine",        // UNIFORM_GRADIENT_LINE
117   "uInvTextSize"          // UNIFORM_INVERSE_TEXT_SIZE
118 };
119
120 }  // <unnamed> namespace
121
122 // IMPLEMENTATION
123
124 Program* Program::New( ProgramCache& cache, Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
125 {
126   size_t shaderHash = shaderData->GetHashValue();
127   Program* program = cache.GetProgram( shaderHash );
128
129   if( NULL == program )
130   {
131     // program not found so create it
132     program = new Program( cache, shaderData, modifiesGeometry );
133
134     // we want to lazy load programs so dont do a Load yet, it gets done in Use()
135
136     cache.AddProgram( shaderHash, program );
137   }
138
139   return program;
140 }
141
142 void Program::Use()
143 {
144   if ( !mLinked )
145   {
146     Load();
147   }
148
149   if ( mLinked )
150   {
151     if ( this != mCache.GetCurrentProgram() )
152     {
153       LOG_GL( "UseProgram(%d)\n", mProgramId );
154       CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(mProgramId) );
155       INCREASE_COUNTER(PerformanceMonitor::SHADER_STATE_CHANGES);
156
157       mCache.SetCurrentProgram( this );
158     }
159   }
160 }
161
162 bool Program::IsUsed()
163 {
164   return ( this == mCache.GetCurrentProgram() );
165 }
166
167 GLint Program::GetAttribLocation( AttribType type )
168 {
169   DALI_ASSERT_DEBUG(type != ATTRIB_UNKNOWN);
170
171   return GetCustomAttributeLocation( type );
172 }
173
174 unsigned int Program::RegisterCustomAttribute( const std::string& name )
175 {
176   unsigned int index = 0;
177   // find the value from cache
178   for( ;index < mAttributeLocations.size(); ++index )
179   {
180     if( mAttributeLocations[ index ].first == name )
181     {
182       // name found so return index
183       return index;
184     }
185   }
186   // if we get here, index is one past end so push back the new name
187   mAttributeLocations.push_back( std::make_pair( name, ATTRIB_UNKNOWN ) );
188   return index;
189 }
190
191 GLint Program::GetCustomAttributeLocation( unsigned int attributeIndex )
192 {
193   // debug check that index is within name cache
194   DALI_ASSERT_DEBUG( mAttributeLocations.size() > attributeIndex );
195
196   // check if we have already queried the location of the attribute
197   GLint location = mAttributeLocations[ attributeIndex ].second;
198
199   if( location == ATTRIB_UNKNOWN )
200   {
201     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetAttribLocation( mProgramId, mAttributeLocations[ attributeIndex ].first.c_str() ) );
202
203     mAttributeLocations[ attributeIndex ].second = location;
204     LOG_GL( "GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[ attributeIndex ].first.c_str(), mAttributeLocations[ attributeIndex ].second );
205   }
206
207   return location;
208 }
209
210
211 unsigned int Program::RegisterUniform( const std::string& name )
212 {
213   unsigned int index = 0;
214   // find the value from cache
215   for( ;index < mUniformLocations.size(); ++index )
216   {
217     if( mUniformLocations[ index ].first == name )
218     {
219       // name found so return index
220       return index;
221     }
222   }
223   // if we get here, index is one past end so push back the new name
224   mUniformLocations.push_back( std::make_pair( name, UNIFORM_NOT_QUERIED ) );
225   return index;
226 }
227
228 GLint Program::GetUniformLocation( unsigned int uniformIndex )
229 {
230   // debug check that index is within name cache
231   DALI_ASSERT_DEBUG( mUniformLocations.size() > uniformIndex );
232
233   // check if we have already queried the location of the uniform
234   GLint location = mUniformLocations[ uniformIndex ].second;
235
236   if( location == UNIFORM_NOT_QUERIED )
237   {
238     location = CHECK_GL( mGlAbstraction, mGlAbstraction.GetUniformLocation( mProgramId, mUniformLocations[ uniformIndex ].first.c_str() ) );
239
240     mUniformLocations[ uniformIndex ].second = location;
241     LOG_GL( "GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[ uniformIndex ].first.c_str(), mUniformLocations[ uniformIndex ].second );
242   }
243
244   return location;
245 }
246
247 void Program::SetUniform1i( GLint location, GLint value0 )
248 {
249   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
250
251   if( UNIFORM_UNKNOWN == location )
252   {
253     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
254     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
255     // specified uniform variable will not be changed.following opengl silently do nothing
256     return;
257   }
258
259   // check if uniform location fits the cache
260   if( location >= MAX_UNIFORM_CACHE_SIZE )
261   {
262     // not cached, make the gl call
263     LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
264     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
265   }
266   else
267   {
268     // check if the value is different from what's already been set
269     if( value0 != mUniformCacheInt[ location ] )
270     {
271       // make the gl call
272       LOG_GL( "Uniform1i(%d,%d)\n", location, value0 );
273       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1i( location, value0 ) );
274       // update cache
275       mUniformCacheInt[ location ] = value0;
276     }
277   }
278 }
279
280 void Program::SetUniform4i( GLint location, GLint value0, GLint value1, GLint value2, GLint value3 )
281 {
282   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
283
284   if( UNIFORM_UNKNOWN == location )
285   {
286     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
287     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
288     // specified uniform variable will not be changed.following opengl silently do nothing
289     return;
290   }
291
292   // Not caching these as based on current analysis this is not called that often by our shaders
293   LOG_GL( "Uniform4i(%d,%d,%d,%d,%d)\n", location, value0, value1, value2, value3 );
294   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4i( location, value0, value1, value2, value3 ) );
295 }
296
297 void Program::SetUniform1f( GLint location, GLfloat value0 )
298 {
299   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
300
301   if( UNIFORM_UNKNOWN == location )
302   {
303     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
304     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
305     // specified uniform variable will not be changed.following opengl silently do nothing
306     return;
307   }
308
309   // check if uniform location fits the cache
310   if( location >= MAX_UNIFORM_CACHE_SIZE )
311   {
312     // not cached, make the gl call
313     LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
314     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
315   }
316   else
317   {
318     // check if the same value has already been set, reset if it is different
319     if( ( fabsf(value0 - mUniformCacheFloat[ location ]) >= Math::MACHINE_EPSILON_1 ) )
320     {
321       // make the gl call
322       LOG_GL( "Uniform1f(%d,%f)\n", location, value0 );
323       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform1f( location, value0 ) );
324
325       // update cache
326       mUniformCacheFloat[ location ] = value0;
327     }
328   }
329 }
330
331 void Program::SetUniform2f( GLint location, GLfloat value0, GLfloat value1 )
332 {
333   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
334
335   if( UNIFORM_UNKNOWN == location )
336   {
337     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
338     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
339     // specified uniform variable will not be changed.following opengl silently do nothing
340     return;
341   }
342
343   // Not caching these as based on current analysis this is not called that often by our shaders
344   LOG_GL( "Uniform2f(%d,%f,%f)\n", location, value0, value1 );
345   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform2f( location, value0, value1 ) );
346 }
347
348 void Program::SetUniform3f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2 )
349 {
350   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
351
352   if( UNIFORM_UNKNOWN == location )
353   {
354     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
355     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
356     // specified uniform variable will not be changed.following opengl silently do nothing
357     return;
358   }
359
360   // Not caching these as based on current analysis this is not called that often by our shaders
361   LOG_GL( "Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2 );
362   CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform3f( location, value0, value1, value2 ) );
363 }
364
365 void Program::SetUniform4f( GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3 )
366 {
367   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
368
369   if( UNIFORM_UNKNOWN == location )
370   {
371     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
372     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
373     // specified uniform variable will not be changed.following opengl silently do nothing
374     return;
375   }
376
377   // check if uniform location fits the cache
378   if( location >= MAX_UNIFORM_CACHE_SIZE )
379   {
380     // not cached, make the gl call
381     LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
382     CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
383   }
384   else
385   {
386     // check if the same value has already been set, reset if any component is different
387     // checking index 3 first because we're often animating alpha (rgba)
388     if( ( fabsf(value3 - mUniformCacheFloat4[ location ][ 3 ]) >= Math::MACHINE_EPSILON_1 )||
389         ( fabsf(value0 - mUniformCacheFloat4[ location ][ 0 ]) >= Math::MACHINE_EPSILON_1 )||
390         ( fabsf(value1 - mUniformCacheFloat4[ location ][ 1 ]) >= Math::MACHINE_EPSILON_1 )||
391         ( fabsf(value2 - mUniformCacheFloat4[ location ][ 2 ]) >= Math::MACHINE_EPSILON_1 ) )
392     {
393       // make the gl call
394       LOG_GL( "Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3 );
395       CHECK_GL( mGlAbstraction, mGlAbstraction.Uniform4f( location, value0, value1, value2, value3 ) );
396       // update cache
397       mUniformCacheFloat4[ location ][ 0 ] = value0;
398       mUniformCacheFloat4[ location ][ 1 ] = value1;
399       mUniformCacheFloat4[ location ][ 2 ] = value2;
400       mUniformCacheFloat4[ location ][ 3 ] = value3;
401     }
402   }
403 }
404
405 void Program::SetUniformMatrix4fv( GLint location, GLsizei count, const GLfloat* value )
406 {
407   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
408
409   if( UNIFORM_UNKNOWN == location )
410   {
411     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
412     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
413     // specified uniform variable will not be changed.following opengl silently do nothing
414     return;
415   }
416
417   // Not caching these calls. Based on current analysis this is called very often
418   // but with different values (we're using this for MVP matrices)
419   // NOTE! we never want driver or GPU to transpose
420   LOG_GL( "UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
421   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix4fv( location, count, GL_FALSE, value ) );
422 }
423
424 void Program::SetUniformMatrix3fv( GLint location, GLsizei count, const GLfloat* value )
425 {
426   DALI_ASSERT_DEBUG( IsUsed() ); // should not call this if this program is not used
427
428   if( UNIFORM_UNKNOWN == location )
429   {
430     // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
431     // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
432     // specified uniform variable will not be changed.following opengl silently do nothing
433     return;
434   }
435
436
437   // Not caching these calls. Based on current analysis this is called very often
438   // but with different values (we're using this for MVP matrices)
439   // NOTE! we never want driver or GPU to transpose
440   LOG_GL( "UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value );
441   CHECK_GL( mGlAbstraction, mGlAbstraction.UniformMatrix3fv( location, count, GL_FALSE, value ) );
442 }
443
444 void Program::GlContextCreated()
445 {
446 }
447
448 void Program::GlContextDestroyed()
449 {
450   mLinked = false;
451   mVertexShaderId = 0;
452   mFragmentShaderId = 0;
453   mProgramId = 0;
454
455   ResetAttribsUniformCache();
456 }
457
458 bool Program::ModifiesGeometry()
459 {
460   return mModifiesGeometry;
461 }
462
463 Program::Program( ProgramCache& cache, Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
464 : mCache( cache ),
465   mGlAbstraction( mCache.GetGlAbstraction() ),
466   mProjectionMatrix( NULL ),
467   mViewMatrix( NULL ),
468   mLinked( false ),
469   mVertexShaderId( 0 ),
470   mFragmentShaderId( 0 ),
471   mProgramId( 0 ),
472   mProgramData(shaderData),
473   mModifiesGeometry( modifiesGeometry )
474 {
475   // reserve space for standard attributes
476   mAttributeLocations.reserve( ATTRIB_TYPE_LAST );
477   for( int i=0; i<ATTRIB_TYPE_LAST; ++i )
478   {
479     RegisterCustomAttribute( gStdAttribs[i] );
480   }
481
482   // reserve space for standard uniforms
483   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
484   // reset built in uniform names in cache
485   for( int i = 0; i < UNIFORM_TYPE_LAST; ++i )
486   {
487     RegisterUniform( gStdUniforms[ i ] );
488   }
489   // reset values
490   ResetAttribsUniformCache();
491 }
492
493 Program::~Program()
494 {
495   Unload();
496 }
497
498 void Program::Load()
499 {
500   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
501
502   LOG_GL( "CreateProgram()\n" );
503   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
504
505   GLint linked = GL_FALSE;
506
507   const bool binariesSupported = mCache.IsBinarySupported();
508
509   // if shader binaries are supported and ShaderData contains compiled bytecode?
510   if( binariesSupported && mProgramData->HasBinary() )
511   {
512     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
513
514     CHECK_GL( mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), mProgramData->GetBufferSize()) );
515
516     CHECK_GL( mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId) );
517
518     GLint success;
519     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_VALIDATE_STATUS, &success ) );
520
521     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
522
523     CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
524
525     if( GL_FALSE == linked )
526     {
527       DALI_LOG_ERROR("Failed to load program binary \n");
528
529       char* szLog = NULL;
530       GLint nLength;
531       CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength) );
532       if(nLength > 0)
533       {
534         szLog = new char[ nLength ];
535         CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog ) );
536         DALI_LOG_ERROR( "Program Link Error: %s\n", szLog );
537
538         delete [] szLog;
539       }
540     }
541     else
542     {
543       mLinked = true;
544     }
545   }
546
547   // Fall back to compiling and linking the vertex and fragment sources
548   if( GL_FALSE == linked )
549   {
550     DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
551     if( CompileShader( GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader() ) )
552     {
553       if( CompileShader( GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader() ) )
554       {
555         Link();
556
557         if( binariesSupported && mLinked )
558         {
559           GLint  binaryLength = 0;
560           GLenum binaryFormat;
561
562           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
563           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
564           if( binaryLength > 0 )
565           {
566             // Allocate space for the bytecode in ShaderData
567             mProgramData->AllocateBuffer(binaryLength);
568             // Copy the bytecode to ShaderData
569             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
570             mCache.StoreBinary( mProgramData );
571           }
572         }
573       }
574     }
575   }
576
577   // No longer needed
578   FreeShaders();
579 }
580
581 void Program::Unload()
582 {
583   FreeShaders();
584
585   if( this == mCache.GetCurrentProgram() )
586   {
587     CHECK_GL( mGlAbstraction, mGlAbstraction.UseProgram(0) );
588
589     mCache.SetCurrentProgram( NULL );
590   }
591
592   if (mProgramId)
593   {
594     LOG_GL( "DeleteProgram(%d)\n", mProgramId );
595     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteProgram( mProgramId ) );
596     mProgramId = 0;
597   }
598
599   mLinked = false;
600
601 }
602
603 bool Program::CompileShader( GLenum shaderType, GLuint& shaderId, const char* src )
604 {
605   if (!shaderId)
606   {
607     LOG_GL( "CreateShader(%d)\n", shaderType );
608     shaderId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateShader( shaderType ) );
609     LOG_GL( "AttachShader(%d,%d)\n", mProgramId, shaderId );
610     CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( mProgramId, shaderId ) );
611   }
612
613   LOG_GL( "ShaderSource(%d)\n", shaderId );
614   CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, NULL ) );
615
616   LOG_GL( "CompileShader(%d)\n", shaderId );
617   CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shaderId ) );
618
619   GLint compiled;
620   LOG_GL( "GetShaderiv(%d)\n", shaderId );
621   CHECK_GL( mGlAbstraction, mGlAbstraction.GetShaderiv( shaderId, GL_COMPILE_STATUS, &compiled ) );
622
623   if (compiled == GL_FALSE)
624   {
625     DALI_LOG_ERROR("Failed to compile shader\n");
626     LogWithLineNumbers(src);
627
628     GLint nLength;
629     mGlAbstraction.GetShaderiv( shaderId, GL_INFO_LOG_LENGTH, &nLength);
630     if(nLength > 0)
631     {
632       Dali::Vector< char > szLog;
633       szLog.Resize( nLength );
634       mGlAbstraction.GetShaderInfoLog( shaderId, nLength, &nLength, szLog.Begin() );
635       DALI_LOG_ERROR( "Shader Compiler Error: %s\n", szLog.Begin() );
636     }
637
638     DALI_ASSERT_ALWAYS( 0 && "Shader compilation failure" );
639   }
640
641   return compiled != 0;
642 }
643
644 void Program::Link()
645 {
646   LOG_GL( "LinkProgram(%d)\n", mProgramId );
647   CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( mProgramId ) );
648
649   GLint linked;
650   LOG_GL( "GetProgramiv(%d)\n", mProgramId );
651   CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv( mProgramId, GL_LINK_STATUS, &linked ) );
652
653   if (linked == GL_FALSE)
654   {
655     DALI_LOG_ERROR("Shader failed to link \n");
656
657     GLint nLength;
658     mGlAbstraction.GetProgramiv( mProgramId, GL_INFO_LOG_LENGTH, &nLength);
659     if(nLength > 0)
660     {
661       Dali::Vector< char > szLog;
662       szLog.Resize( nLength );
663       mGlAbstraction.GetProgramInfoLog( mProgramId, nLength, &nLength, szLog.Begin() );
664       DALI_LOG_ERROR( "Shader Link Error: %s\n", szLog.Begin() );
665     }
666
667     DALI_ASSERT_ALWAYS( 0 && "Shader linking failure" );
668   }
669
670   mLinked = linked != GL_FALSE;
671 }
672
673 void Program::FreeShaders()
674 {
675   if (mVertexShaderId)
676   {
677     LOG_GL( "DeleteShader(%d)\n", mVertexShaderId );
678     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mVertexShaderId ) );
679     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mVertexShaderId ) );
680     mVertexShaderId = 0;
681   }
682
683   if (mFragmentShaderId)
684   {
685     LOG_GL( "DeleteShader(%d)\n", mFragmentShaderId );
686     CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( mProgramId, mFragmentShaderId ) );
687     CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( mFragmentShaderId ) );
688     mFragmentShaderId = 0;
689   }
690 }
691
692 void Program::ResetAttribsUniformCache()
693 {
694   // reset attribute locations
695   for( unsigned i = 0; i < mAttributeLocations.size() ; ++i )
696   {
697     mAttributeLocations[ i ].second = ATTRIB_UNKNOWN;
698   }
699
700   // reset all gl uniform locations
701   for( unsigned int i = 0; i < mUniformLocations.size(); ++i )
702   {
703     // reset gl program locations and names
704     mUniformLocations[ i ].second = UNIFORM_NOT_QUERIED;
705   }
706
707   // reset uniform cache
708   for( int i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i )
709   {
710     // GL initializes uniforms to 0
711     mUniformCacheInt[ i ] = 0;
712     mUniformCacheFloat[ i ] = 0.0f;
713     mUniformCacheFloat4[ i ][ 0 ] = 0.0f;
714     mUniformCacheFloat4[ i ][ 1 ] = 0.0f;
715     mUniformCacheFloat4[ i ][ 2 ] = 0.0f;
716     mUniformCacheFloat4[ i ][ 3 ] = 0.0f;
717   }
718 }
719
720 } // namespace Internal
721
722 } // namespace Dali