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