Merge remote-tracking branch 'origin/tizen' into new_text
[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/gl-resources/context.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 template <> struct ParameterType< Dali::ShaderEffect::GeometryHints> : public BasicType< Dali::ShaderEffect::GeometryHints > {};
71 template <> struct ParameterType< Dali::ShaderEffect::UniformCoordinateType > : public BasicType< Dali::ShaderEffect::UniformCoordinateType > {};
72
73 namespace SceneGraph
74 {
75
76 namespace // unnamed namespace
77 {
78
79 // Convert Geometry type bitmask to an array index
80 inline unsigned int GetGeometryTypeIndex(GeometryType type)
81 {
82   unsigned int index = Log<GEOMETRY_TYPE_IMAGE>::value;
83   if ( type & GEOMETRY_TYPE_IMAGE )
84   {
85     index = Log<GEOMETRY_TYPE_IMAGE>::value;
86   }
87   else if ( type & GEOMETRY_TYPE_UNTEXTURED_MESH )
88   {
89     index = Log<GEOMETRY_TYPE_UNTEXTURED_MESH>::value;
90   }
91   else if ( type & GEOMETRY_TYPE_TEXTURED_MESH )
92   {
93     index = Log<GEOMETRY_TYPE_TEXTURED_MESH>::value;
94   }
95   return index;
96 }
97
98 } // unnamed namespace
99
100
101
102
103 Shader::Shader( Dali::ShaderEffect::GeometryHints& hints )
104 : mGeometryHints( hints ),
105   mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
106   mTexture( NULL ),
107   mRenderTextureId( 0 ),
108   mUpdateTextureId( 0 ),
109   mRenderQueue(NULL),
110   mTextureCache(NULL)
111 {
112   // Create enough size for all default types and sub-types
113   mPrograms.resize(Log<GEOMETRY_TYPE_LAST>::value);
114   for( unsigned int i = 0; i < Log<GEOMETRY_TYPE_LAST>::value; ++i)
115   {
116     mPrograms[ i ].Resize(SHADER_SUBTYPE_LAST);
117   }
118 }
119
120 Shader::~Shader()
121 {
122 }
123
124 void Shader::Initialize( RenderQueue& renderQueue, TextureCache& textureCache )
125 {
126   mRenderQueue = &renderQueue;
127   mTextureCache = &textureCache;
128 }
129
130 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131 // The following methods are called during UpdateManager::Update()
132 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
133
134 void Shader::ForwardTextureId( BufferIndex updateBufferIndex, ResourceId textureId )
135 {
136   mUpdateTextureId = textureId;
137
138   typedef MessageValue1< Shader, Integration::ResourceId > DerivedType;
139
140   // Reserve some memory inside the render queue
141   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
142
143   // Construct message in the render queue memory; note that delete should not be called on the return value
144   new (slot) DerivedType( this, &Shader::SetTextureId, textureId );
145 }
146
147 Integration::ResourceId Shader::GetEffectTextureResourceId()
148 {
149   return mUpdateTextureId;
150 }
151
152 void Shader::ForwardUniformMeta( BufferIndex updateBufferIndex, UniformMeta* meta )
153 {
154   // Defer setting uniform metadata until the next Render
155
156   typedef MessageValue1< Shader, UniformMeta* > DerivedType;
157
158   // Reserve some memory inside the render queue
159   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
160
161   // Construct message in the render queue memory; note that delete should not be called on the return value
162   new (slot) DerivedType( this, &Shader::InstallUniformMetaInRender, meta );
163 }
164
165 void Shader::ForwardCoordinateType( BufferIndex updateBufferIndex, unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
166 {
167   // Defer setting uniform coordinate type until the next Render
168   typedef MessageValue2< Shader, unsigned int, Dali::ShaderEffect::UniformCoordinateType > DerivedType;
169
170   // Reserve some memory inside the render queue
171   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
172
173   // Construct message in the render queue memory; note that delete should not be called on the return value
174   new (slot) DerivedType( this, &Shader::SetCoordinateTypeInRender, index, type );
175 }
176
177 void Shader::ForwardGridDensity( BufferIndex updateBufferIndex, float density )
178 {
179   typedef MessageValue1< Shader, float > DerivedType;
180
181   // Reserve some memory inside the render queue
182   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
183
184   // Construct message in the render queue memory; note that delete should not be called on the return value
185   new (slot) DerivedType( this, &Shader::SetGridDensity, density );
186 }
187
188 void Shader::ForwardHints( BufferIndex updateBufferIndex, Dali::ShaderEffect::GeometryHints hint )
189 {
190   typedef MessageValue1< Shader, Dali::ShaderEffect::GeometryHints > DerivedType;
191
192   // Reserve some memory inside the render queue
193   unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
194
195   // Construct message in the render queue memory; note that delete should not be called on the return value
196   new (slot) DerivedType( this, &Shader::SetGeometryHints, hint );
197 }
198
199 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 // The following methods are called during RenderManager::Render()
201 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
202
203 void Shader::SetTextureId( Integration::ResourceId textureId )
204 {
205   if ( mRenderTextureId != textureId )
206   {
207     mRenderTextureId = textureId;
208     mTexture = NULL;
209   }
210 }
211
212 Integration::ResourceId Shader::GetTextureIdToRender()
213 {
214   return mRenderTextureId;
215 }
216
217 void Shader::SetGridDensity( float density )
218 {
219   mGridDensity = density;
220 }
221
222 float Shader::GetGridDensity()
223 {
224   return mGridDensity;
225 }
226
227 void Shader::InstallUniformMetaInRender( UniformMeta* meta )
228 {
229   mUniformMetadata.PushBack( meta );
230 }
231
232 void Shader::SetCoordinateTypeInRender( unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
233 {
234   DALI_ASSERT_DEBUG( index < mUniformMetadata.Count() );
235   mUniformMetadata[ index ]->SetCoordinateType( type );
236 }
237
238 void Shader::SetProgram( GeometryType geometryType,
239                          ShaderSubTypes subType,
240                          Integration::ResourceId resourceId,
241                          Integration::ShaderDataPtr shaderData,
242                          ProgramCache* programCache,
243                          bool modifiesGeometry )
244 {
245   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d %d\n", (int)geometryType, resourceId);
246
247   Program* program = Program::New( *programCache, shaderData, modifiesGeometry );
248
249   ShaderSubTypes theSubType = subType;
250   if( subType == SHADER_SUBTYPE_ALL )
251   {
252     theSubType = SHADER_DEFAULT;
253   }
254
255   const unsigned int geometryIndex = GetGeometryTypeIndex( geometryType );
256   if(subType == SHADER_SUBTYPE_ALL)
257   {
258     mPrograms[geometryIndex].Resize(1);
259     mPrograms[geometryIndex][theSubType] = program;
260     mPrograms[geometryIndex].mUseDefaultForAllSubtypes = true;
261   }
262   else
263   {
264     mPrograms[geometryIndex][theSubType] = program;
265     mPrograms[geometryIndex].mUseDefaultForAllSubtypes = false;
266   }
267 }
268
269 bool Shader::AreSubtypesRequired(GeometryType geometryType)
270 {
271   DALI_ASSERT_DEBUG(geometryType < GEOMETRY_TYPE_LAST);
272   unsigned int programType = GetGeometryTypeIndex( geometryType );
273
274   return ! mPrograms[ programType ].mUseDefaultForAllSubtypes;
275 }
276
277 Program* Shader::GetProgram( Context& context,
278                              GeometryType type,
279                              ShaderSubTypes subType,
280                              unsigned int& programIndex )
281 {
282   DALI_ASSERT_DEBUG(type < GEOMETRY_TYPE_LAST);
283   DALI_DEBUG_OSTREAM(debugStream);
284
285   programIndex = GetGeometryTypeIndex( type );
286
287   DALI_ASSERT_DEBUG((unsigned int)subType < mPrograms[ programIndex ].Count());
288
289   return mPrograms[ programIndex ][ subType ];
290 }
291
292
293 void Shader::SetUniforms( Context& context,
294                           Program& program,
295                           BufferIndex bufferIndex,
296                           unsigned int programIndex,
297                           ShaderSubTypes subType )
298 {
299   DALI_ASSERT_DEBUG( programIndex < Log<GEOMETRY_TYPE_LAST>::value );
300   DALI_DEBUG_OSTREAM(debugStream);
301
302   if( mRenderTextureId && ( mTexture == NULL ) )
303   {
304     mTexture = mTextureCache->GetTexture( mRenderTextureId );
305
306     DALI_ASSERT_DEBUG( mTexture != NULL );
307   }
308
309   GLint loc = Program::UNIFORM_UNKNOWN;
310
311   if( mTexture )
312   {
313     // if effect sampler uniform used by the program ?
314     const GLint loc = program.GetUniformLocation( Program::UNIFORM_EFFECT_SAMPLER );
315     if( Program::UNIFORM_UNKNOWN != loc )
316     {
317       // got effect texture, bind it to texture unit 1
318       mTextureCache->BindTexture( mTexture, mRenderTextureId, GL_TEXTURE_2D, TEXTURE_UNIT_SHADER);
319
320       // Apply the default sampling options for now
321       mTexture->ApplySampler( TEXTURE_UNIT_SHADER, ImageSampler::PackBitfield( FilterMode::DEFAULT, FilterMode::DEFAULT ) );
322
323       DALI_PRINT_UNIFORM( debugStream, bufferIndex, "sEffect", TEXTURE_UNIT_SHADER );
324       // set the uniform
325       program.SetUniform1i( loc, TEXTURE_UNIT_SHADER );
326     }
327   }
328
329   // We should have one UniformMeta per uniform property
330   for ( unsigned int i = 0u; i < mUniformMetadata.Count(); ++i )
331   {
332     UniformMeta& metadata = *mUniformMetadata[i];
333     const PropertyBase& property = metadata.property;
334
335     // send the updated uniform to the program
336     if ( metadata.name.length() > 0 )
337     {
338       // 0 means program has not got a cache index for this uniform
339       if( 0 == metadata.cacheIndeces[ programIndex ][ subType ] )
340       {
341         // register cacheindex for this program
342         metadata.cacheIndeces[ programIndex ][ subType ] = program.RegisterUniform( metadata.name );
343       }
344       loc = program.GetUniformLocation( metadata.cacheIndeces[ programIndex ][ subType ] );
345
346       // if we find uniform with location
347       if ( Program::UNIFORM_UNKNOWN != loc )
348       {
349         DALI_PRINT_CUSTOM_UNIFORM( debugStream, bufferIndex, metadata.name, property );
350
351         // switch based on property type to use correct GL uniform setter
352         switch ( property.GetType() )
353         {
354           case Property::FLOAT :
355           {
356             program.SetUniform1f( loc, property.GetFloat( bufferIndex ) );
357             break;
358           }
359           case Property::INTEGER :
360           {
361             program.SetUniform1i( loc, property.GetInteger( bufferIndex ) );
362             break;
363           }
364           case Property::VECTOR2 :
365           {
366             Vector2 value( property.GetVector2( bufferIndex ) );
367
368             switch ( metadata.coordinateType )
369             {
370               case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION :
371               {
372                 /**
373                  * Convert coordinates from viewport to GL view space
374                  *
375                  * Viewport coordinate
376                  * (0,0)
377                  *      +-----+
378                  *      |     |
379                  *      |     |
380                  *      +-----+
381                  *             (width,height)
382                  *
383                  * GL view space coordinates
384                  * (width/2,-height/2)
385                  *      +-----+
386                  *      |     |
387                  *      |     |
388                  *      +-----+
389                  *             (-width/2,height/2)
390                  **/
391                 const Rect< int >& viewport = context.GetViewport();
392                 value.x = viewport.width * 0.5f - value.x;
393                 value.y = value.y - viewport.height * 0.5f;
394
395                 break;
396               }
397               case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION :
398               {
399                 // Check diagram in COORDINATE_TYPE_VIEWPORT_POSITION
400                 value.x *= -1.0f;
401                 break;
402               }
403               case Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT :
404               {
405                 // nothing to do in this case
406                 break;
407               }
408               // no default so compiler will warn if a case is not handled
409             }
410
411             program.SetUniform2f( loc, value.x, value.y );
412             break;
413           }
414
415           case Property::VECTOR3 :
416           {
417             Vector3 value( property.GetVector3( bufferIndex ) );
418             if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
419             {
420               value.y *= -1.0f;
421             }
422
423             program.SetUniform3f( loc, value.x, value.y, value.z );
424             break;
425           }
426
427           case Property::VECTOR4 :
428           {
429             Vector4 value( property.GetVector4( bufferIndex ) );
430             if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
431             {
432               value.y *= -1.0f;
433             }
434
435             program.SetUniform4f( loc, value.x, value.y, value.z, value.w );
436             break;
437           }
438
439           case Property::MATRIX:
440           {
441             const Matrix& value = property.GetMatrix(bufferIndex);
442             program.SetUniformMatrix4fv(loc, 1, value.AsFloat() );
443             break;
444           }
445
446           case Property::MATRIX3:
447           {
448             const Matrix3& value = property.GetMatrix3(bufferIndex);
449             program.SetUniformMatrix3fv(loc, 1, value.AsFloat() );
450             break;
451           }
452
453           default :
454           {
455             // Only float and Vector properties are passed as uniforms; other types are ignored.
456             break;
457           }
458         }
459       }
460     }
461   }
462
463   DALI_PRINT_SHADER_UNIFORMS(debugStream);
464 }
465
466
467 // Messages
468
469 void SetTextureIdMessage( EventToUpdate& eventToUpdate, const Shader& shader, Integration::ResourceId textureId )
470 {
471   typedef MessageDoubleBuffered1< Shader, Integration::ResourceId > LocalType;
472
473   // Reserve some memory inside the message queue
474   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
475
476   // Construct message in the message queue memory; note that delete should not be called on the return value
477   new (slot) LocalType( &shader, &Shader::ForwardTextureId, textureId );
478 }
479
480 void SetGridDensityMessage( EventToUpdate& eventToUpdate, const Shader& shader, float density )
481 {
482   typedef MessageDoubleBuffered1< Shader, float > LocalType;
483
484   // Reserve some memory inside the message queue
485   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
486
487   // Construct message in the message queue memory; note that delete should not be called on the return value
488   new (slot) LocalType( &shader, &Shader::ForwardGridDensity, density );
489 }
490
491 void SetHintsMessage( EventToUpdate& eventToUpdate, const Shader& shader, Dali::ShaderEffect::GeometryHints hint )
492 {
493   typedef MessageDoubleBuffered1< Shader, Dali::ShaderEffect::GeometryHints > LocalType;
494
495   // Reserve some memory inside the message queue
496   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
497
498   // Construct message in the message queue memory; note that delete should not be called on the return value
499   new (slot) LocalType( &shader, &Shader::ForwardHints, hint );
500 }
501
502 void InstallUniformMetaMessage( EventToUpdate& eventToUpdate, const Shader& shader, UniformMeta& meta )
503 {
504   typedef MessageDoubleBuffered1< Shader, UniformMeta* > LocalType;
505
506   // Reserve some memory inside the message queue
507   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
508
509   // Construct message in the message queue memory; note that delete should not be called on the return value
510   new (slot) LocalType( &shader, &Shader::ForwardUniformMeta, &meta );
511 }
512
513 void SetCoordinateTypeMessage( EventToUpdate& eventToUpdate, const Shader& shader, unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
514 {
515   typedef MessageDoubleBuffered2< Shader, unsigned int, Dali::ShaderEffect::UniformCoordinateType > LocalType;
516
517   // Reserve some memory inside the message queue
518   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
519
520   // Construct message in the message queue memory; note that delete should not be called on the return value
521   new (slot) LocalType( &shader, &Shader::ForwardCoordinateType, index, type );
522 }
523
524
525 } // namespace SceneGraph
526
527 } // namespace Internal
528
529 } // namespace Dali