fix shader binary compilation to work with lazy compilation
[platform/core/uifw/dali-core.git] / dali / internal / render / shaders / shader.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/shader.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/render/queue/render-queue.h>
23 #include <dali/internal/render/common/render-debug.h>
24 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
25 #include <dali/internal/render/gl-resources/texture.h>
26 #include <dali/internal/render/gl-resources/texture-cache.h>
27 #include <dali/internal/render/gl-resources/texture-units.h>
28 #include <dali/internal/render/shaders/program.h>
29 #include <dali/internal/render/shaders/uniform-meta.h>
30 #include <dali/internal/common/image-sampler.h>
31
32 // See render-debug.h
33 #ifdef DALI_PRINT_RENDER_INFO
34
35 #include <sstream>
36 #define DALI_DEBUG_OSTREAM(streamName) std::stringstream streamName;
37
38 #define DALI_PRINT_UNIFORM(streamName,bufferIndex,name,value) \
39   { \
40     streamName << " " << name << ": " << value; \
41   }
42
43 #define DALI_PRINT_CUSTOM_UNIFORM(streamName,bufferIndex,name,property) \
44   { \
45     streamName << " " << name << ": "; \
46     property.DebugPrint( streamName, bufferIndex ); \
47   }
48
49 #define DALI_PRINT_SHADER_UNIFORMS(streamName) \
50   { \
51     std::string debugString( streamName.str() ); \
52     DALI_LOG_RENDER_INFO( "           %s\n", debugString.c_str() ); \
53   }
54
55 #else // DALI_PRINT_RENDER_INFO
56
57 #define DALI_DEBUG_OSTREAM(streamName)
58 #define DALI_PRINT_UNIFORM(streamName,bufferIndex,name,value)
59 #define DALI_PRINT_CUSTOM_UNIFORM(streamName,bufferIndex,name,property)
60 #define DALI_PRINT_SHADER_UNIFORMS(streamName)
61
62 #endif // DALI_PRINT_RENDER_INFO
63
64 namespace Dali
65 {
66
67 namespace Internal
68 {
69
70 namespace SceneGraph
71 {
72
73 namespace // unnamed namespace
74 {
75
76 // Convert Geometry type bitmask to an array index
77 inline unsigned int GetGeometryTypeIndex(GeometryType type)
78 {
79   unsigned int index = Log<GEOMETRY_TYPE_IMAGE>::value;
80   if ( type & GEOMETRY_TYPE_IMAGE )
81   {
82     index = Log<GEOMETRY_TYPE_IMAGE>::value;
83   }
84   else if ( type & GEOMETRY_TYPE_TEXT )
85   {
86     index = Log<GEOMETRY_TYPE_TEXT>::value;
87   }
88   else if ( type & GEOMETRY_TYPE_UNTEXTURED_MESH )
89   {
90     index = Log<GEOMETRY_TYPE_UNTEXTURED_MESH>::value;
91   }
92   else if ( type & GEOMETRY_TYPE_TEXTURED_MESH )
93   {
94     index = Log<GEOMETRY_TYPE_TEXTURED_MESH>::value;
95   }
96   return index;
97 }
98
99 } // unnamed namespace
100
101
102
103
104 Shader::Shader( Dali::ShaderEffect::GeometryHints& hints )
105 : mGeometryHints( hints ),
106   mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
107   mTexture( NULL ),
108   mRenderTextureId( 0 ),
109   mUpdateTextureId( 0 ),
110   mRenderQueue(NULL),
111   mPostProcessDispatcher(NULL),
112   mTextureCache(NULL)
113 {
114   // Create enough size for all default types and sub-types
115   mPrograms.resize(Log<GEOMETRY_TYPE_LAST>::value);
116   for( unsigned int i = 0; i < Log<GEOMETRY_TYPE_LAST>::value; ++i)
117   {
118     mPrograms[ i ].Resize(SHADER_SUBTYPE_LAST);
119   }
120 }
121
122 Shader::~Shader()
123 {
124 }
125
126 void Shader::Initialize( PostProcessResourceDispatcher& postProcessDispatcher, RenderQueue& renderQueue, TextureCache& textureCache )
127 {
128   mPostProcessDispatcher = &postProcessDispatcher;
129   mRenderQueue = &renderQueue;
130   mTextureCache = &textureCache;
131 }
132
133 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
134 // The following methods are called during UpdateManager::Update()
135 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136
137 void Shader::ForwardTextureId( BufferIndex updateBufferIndex, ResourceId textureId )
138 {
139   mUpdateTextureId = textureId;
140
141   typedef MessageValue1< Shader, Integration::ResourceId > DerivedType;
142
143   // Reserve some memory inside the render queue
144   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
145
146   // Construct message in the render queue memory; note that delete should not be called on the return value
147   new (slot) DerivedType( this, &Shader::SetTextureId, textureId );
148 }
149
150 Integration::ResourceId Shader::GetEffectTextureResourceId()
151 {
152   return mUpdateTextureId;
153 }
154
155 void Shader::ForwardUniformMeta( BufferIndex updateBufferIndex, UniformMeta* meta )
156 {
157   // Defer setting uniform metadata until the next Render
158   // (Maintains thread safety on std::vector)
159
160   typedef MessageValue1< Shader, UniformMeta* > DerivedType;
161
162   // Reserve some memory inside the render queue
163   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
164
165   // Construct message in the render queue memory; note that delete should not be called on the return value
166   new (slot) DerivedType( this, &Shader::InstallUniformMetaInRender, meta );
167 }
168
169 void Shader::ForwardGridDensity( BufferIndex updateBufferIndex, float density )
170 {
171   typedef MessageValue1< Shader, float > DerivedType;
172
173   // Reserve some memory inside the render queue
174   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
175
176   // Construct message in the render queue memory; note that delete should not be called on the return value
177   new (slot) DerivedType( this, &Shader::SetGridDensity, density );
178 }
179
180 void Shader::ForwardHints( BufferIndex updateBufferIndex, Dali::ShaderEffect::GeometryHints hint )
181 {
182   typedef MessageValue1< Shader, Dali::ShaderEffect::GeometryHints > DerivedType;
183
184   // Reserve some memory inside the render queue
185   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
186
187   // Construct message in the render queue memory; note that delete should not be called on the return value
188   new (slot) DerivedType( this, &Shader::SetGeometryHints, hint );
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
192 // The following methods are called during RenderManager::Render()
193 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194
195 void Shader::SetTextureId( Integration::ResourceId textureId )
196 {
197   if ( mRenderTextureId != textureId )
198   {
199     mRenderTextureId = textureId;
200     mTexture = NULL;
201   }
202 }
203
204 Integration::ResourceId Shader::GetTextureIdToRender()
205 {
206   return mRenderTextureId;
207 }
208
209 void Shader::SetGridDensity( float density )
210 {
211   mGridDensity = density;
212 }
213
214 float Shader::GetGridDensity()
215 {
216   return mGridDensity;
217 }
218
219 void Shader::InstallUniformMetaInRender( UniformMeta* meta )
220 {
221   mUniformMetadata.PushBack( meta );
222 }
223
224 void Shader::SetProgram( GeometryType geometryType,
225                          ShaderSubTypes subType,
226                          Integration::ResourceId resourceId,
227                          Integration::ShaderDataPtr shaderData,
228                          Context* context,
229                          bool modifiesGeometry )
230 {
231   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d %d\n", (int)geometryType, resourceId);
232
233   bool precompiledBinary = shaderData->HasBinary();
234
235   Program* program = Program::New( resourceId, shaderData, *context, modifiesGeometry );
236
237   ShaderSubTypes theSubType = subType;
238   if( subType == SHADER_SUBTYPE_ALL )
239   {
240     theSubType = SHADER_DEFAULT;
241   }
242
243   const unsigned int geometryIndex = GetGeometryTypeIndex( geometryType );
244   if(geometryType != GEOMETRY_TYPE_TEXT && subType == SHADER_SUBTYPE_ALL)
245   {
246     mPrograms[geometryIndex].Resize(1);
247     mPrograms[geometryIndex][theSubType] = program;
248     mPrograms[geometryIndex].mUseDefaultForAllSubtypes = true;
249   }
250   else
251   {
252     mPrograms[geometryIndex][theSubType] = program;
253     mPrograms[geometryIndex].mUseDefaultForAllSubtypes = false;
254   }
255
256   // if platform supports program binaries and we haven't yet saved a binary
257   if( context->CachedNumberOfProgramBinaryFormats() > 0 && !precompiledBinary )
258   {
259     // this is the first time this shader is being used so force compilation
260     program->Load();
261
262     // The binary should now have been compiled/linked, so save it
263     if( shaderData->HasBinary() )
264     {
265       DALI_ASSERT_DEBUG( mPostProcessDispatcher != NULL );
266       ResourcePostProcessRequest request( resourceId, ResourcePostProcessRequest::SAVE );
267       mPostProcessDispatcher->DispatchPostProcessRequest( request );
268     }
269   }
270 }
271
272 bool Shader::AreSubtypesRequired(GeometryType geometryType)
273 {
274   DALI_ASSERT_DEBUG(geometryType < GEOMETRY_TYPE_LAST);
275   unsigned int programType = GetGeometryTypeIndex( geometryType );
276
277   return ! mPrograms[ programType ].mUseDefaultForAllSubtypes;
278 }
279
280 Program* Shader::GetProgram( Context& context,
281                              GeometryType type,
282                              ShaderSubTypes subType,
283                              unsigned int& programIndex )
284 {
285   DALI_ASSERT_DEBUG(type < GEOMETRY_TYPE_LAST);
286   DALI_DEBUG_OSTREAM(debugStream);
287
288   programIndex = GetGeometryTypeIndex( type );
289
290   DALI_ASSERT_DEBUG((unsigned int)subType < mPrograms[ programIndex ].Count());
291
292   return mPrograms[ programIndex ][ subType ];
293 }
294
295
296 void Shader::SetUniforms( Context& context,
297                           Program& program,
298                           BufferIndex bufferIndex,
299                           unsigned int programIndex,
300                           ShaderSubTypes subType )
301 {
302   DALI_ASSERT_DEBUG( programIndex < Log<GEOMETRY_TYPE_LAST>::value );
303   DALI_DEBUG_OSTREAM(debugStream);
304
305   if( mRenderTextureId && ( mTexture == NULL ) )
306   {
307     mTexture = mTextureCache->GetTexture( mRenderTextureId );
308
309     DALI_ASSERT_DEBUG( mTexture != NULL );
310   }
311
312   GLint loc = Program::UNIFORM_UNKNOWN;
313
314   if( mTexture )
315   {
316     // got effect texture, bind it to texture unit 1
317     mTextureCache->BindTexture( mTexture, mRenderTextureId, GL_TEXTURE_2D, TEXTURE_UNIT_SHADER);
318
319     // Just apply the default sampling options for now
320     mTexture->ApplySampler( TEXTURE_UNIT_SHADER, ImageSampler::PackBitfield( FilterMode::DEFAULT, FilterMode::DEFAULT ) );
321
322     // get effect sampler uniform
323     const GLint loc = program.GetUniformLocation( Program::UNIFORM_EFFECT_SAMPLER );
324     if( Program::UNIFORM_UNKNOWN != loc )
325     {
326       DALI_PRINT_UNIFORM( debugStream, bufferIndex, "sEffect", TEXTURE_UNIT_SHADER );
327       // set the uniform
328       program.SetUniform1i( loc, TEXTURE_UNIT_SHADER );
329     }
330   }
331
332   // We should have one UniformMeta per uniform property
333   for ( unsigned int i = 0u; i < mUniformMetadata.Count(); ++i )
334   {
335     UniformMeta& metadata = *mUniformMetadata[i];
336     const PropertyBase& property = metadata.property;
337
338     // send the updated uniform to the program
339     if ( metadata.name.length() > 0 )
340     {
341       // 0 means program has not got a cache index for this uniform
342       if( 0 == metadata.cacheIndeces[ programIndex ][ subType ] )
343       {
344         // register cacheindex for this program
345         metadata.cacheIndeces[ programIndex ][ subType ] = program.RegisterUniform( metadata.name );
346       }
347       loc = program.GetUniformLocation( metadata.cacheIndeces[ programIndex ][ subType ] );
348
349       // if we find uniform with location
350       if ( Program::UNIFORM_UNKNOWN != loc )
351       {
352         DALI_PRINT_CUSTOM_UNIFORM( debugStream, bufferIndex, metadata.name, property );
353
354         // switch based on property type to use correct GL uniform setter
355         switch ( property.GetType() )
356         {
357           case Property::FLOAT :
358           {
359             program.SetUniform1f( loc, property.GetFloat( bufferIndex ) );
360             break;
361           }
362           case Property::INTEGER :
363           {
364             program.SetUniform1i( loc, property.GetInteger( bufferIndex ) );
365             break;
366           }
367           case Property::VECTOR2 :
368           {
369             Vector2 value( property.GetVector2( bufferIndex ) );
370
371             switch ( metadata.coordinateType )
372             {
373               case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION :
374               {
375                 /**
376                  * Convert coordinates from viewport to GL view space
377                  *
378                  * Viewport coordinate
379                  * (0,0)
380                  *      +-----+
381                  *      |     |
382                  *      |     |
383                  *      +-----+
384                  *             (width,height)
385                  *
386                  * GL view space coordinates
387                  * (width/2,-height/2)
388                  *      +-----+
389                  *      |     |
390                  *      |     |
391                  *      +-----+
392                  *             (-width/2,height/2)
393                  **/
394                 const Rect< int >& viewport = context.GetViewport();
395                 value.x = viewport.width * 0.5f - value.x;
396                 value.y = value.y - viewport.height * 0.5f;
397
398                 break;
399               }
400               case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION :
401               {
402                 // Check diagram in COORDINATE_TYPE_VIEWPORT_POSITION
403                 value.x *= -1.0f;
404                 break;
405               }
406               case Dali::ShaderEffect::COORDINATE_TYPE_TEXTURE_POSITION :
407               {
408                 if ( mTexture )
409                 {
410                   UvRect textureArea;
411                   mTexture->GetTextureCoordinates( textureArea );
412
413                   //TODO: this only works for textures that are mapped as a axis aligned rectangle
414                   float width = textureArea.u2 - textureArea.u0;
415                   float height = textureArea.v2 - textureArea.v0;
416                   value.x = textureArea.u0 + value.x * width;
417                   value.y = textureArea.v0 + value.y * height;
418                 }
419                 break;
420               }
421               case Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT :
422               {
423                 // nothing to do in this case
424                 break;
425               }
426               // no default so compiler will warn if a case is not handled
427             }
428
429             program.SetUniform2f( loc, value.x, value.y );
430             break;
431           }
432
433           case Property::VECTOR3 :
434           {
435             Vector3 value( property.GetVector3( bufferIndex ) );
436             if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
437             {
438               value.y *= -1.0f;
439             }
440
441             program.SetUniform3f( loc, value.x, value.y, value.z );
442             break;
443           }
444
445           case Property::VECTOR4 :
446           {
447             Vector4 value( property.GetVector4( bufferIndex ) );
448             if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
449             {
450               value.y *= -1.0f;
451             }
452
453             program.SetUniform4f( loc, value.x, value.y, value.z, value.w );
454             break;
455           }
456
457           case Property::MATRIX:
458           {
459             const Matrix& value = property.GetMatrix(bufferIndex);
460             program.SetUniformMatrix4fv(loc, 1, value.AsFloat() );
461             break;
462           }
463
464           case Property::MATRIX3:
465           {
466             const Matrix3& value = property.GetMatrix3(bufferIndex);
467             program.SetUniformMatrix3fv(loc, 1, value.AsFloat() );
468             break;
469           }
470
471           default :
472           {
473             // Only float and Vector properties are passed as uniforms; other types are ignored.
474             break;
475           }
476         }
477       }
478     }
479   }
480
481   DALI_PRINT_SHADER_UNIFORMS(debugStream);
482 }
483
484 } // namespace SceneGraph
485
486 } // namespace Internal
487
488 } // namespace Dali