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