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