2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/shaders/shader.h>
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>
33 #ifdef DALI_PRINT_RENDER_INFO
36 #define DALI_DEBUG_OSTREAM(streamName) std::stringstream streamName;
38 #define DALI_PRINT_UNIFORM(streamName,bufferIndex,name,value) \
40 streamName << " " << name << ": " << value; \
43 #define DALI_PRINT_CUSTOM_UNIFORM(streamName,bufferIndex,name,property) \
45 streamName << " " << name << ": "; \
46 property.DebugPrint( streamName, bufferIndex ); \
49 #define DALI_PRINT_SHADER_UNIFORMS(streamName) \
51 std::string debugString( streamName.str() ); \
52 DALI_LOG_RENDER_INFO( " %s\n", debugString.c_str() ); \
55 #else // DALI_PRINT_RENDER_INFO
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)
62 #endif // DALI_PRINT_RENDER_INFO
70 template <> struct ParameterType< Dali::ShaderEffect::GeometryHints> : public BasicType< Dali::ShaderEffect::GeometryHints > {};
71 template <> struct ParameterType< Dali::ShaderEffect::UniformCoordinateType > : public BasicType< Dali::ShaderEffect::UniformCoordinateType > {};
76 namespace // unnamed namespace
79 // Convert Geometry type bitmask to an array index
80 inline unsigned int GetGeometryTypeIndex(GeometryType type)
82 unsigned int index = Log<GEOMETRY_TYPE_IMAGE>::value;
83 if ( type & GEOMETRY_TYPE_IMAGE )
85 index = Log<GEOMETRY_TYPE_IMAGE>::value;
87 else if ( type & GEOMETRY_TYPE_UNTEXTURED_MESH )
89 index = Log<GEOMETRY_TYPE_UNTEXTURED_MESH>::value;
91 else if ( type & GEOMETRY_TYPE_TEXTURED_MESH )
93 index = Log<GEOMETRY_TYPE_TEXTURED_MESH>::value;
98 } // unnamed namespace
103 Shader::Shader( Dali::ShaderEffect::GeometryHints& hints )
104 : mGeometryHints( hints ),
105 mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
107 mRenderTextureId( 0 ),
108 mUpdateTextureId( 0 ),
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)
116 mPrograms[ i ].Resize(SHADER_SUBTYPE_LAST);
124 void Shader::Initialize( RenderQueue& renderQueue, TextureCache& textureCache )
126 mRenderQueue = &renderQueue;
127 mTextureCache = &textureCache;
130 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131 // The following methods are called during UpdateManager::Update()
132 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
134 void Shader::ForwardTextureId( BufferIndex updateBufferIndex, ResourceId textureId )
136 mUpdateTextureId = textureId;
138 typedef MessageValue1< Shader, Integration::ResourceId > DerivedType;
140 // Reserve some memory inside the render queue
141 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
147 Integration::ResourceId Shader::GetEffectTextureResourceId()
149 return mUpdateTextureId;
152 void Shader::ForwardUniformMeta( BufferIndex updateBufferIndex, UniformMeta* meta )
154 // Defer setting uniform metadata until the next Render
156 typedef MessageValue1< Shader, UniformMeta* > DerivedType;
158 // Reserve some memory inside the render queue
159 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
165 void Shader::ForwardCoordinateType( BufferIndex updateBufferIndex, unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
167 // Defer setting uniform coordinate type until the next Render
168 typedef MessageValue2< Shader, unsigned int, Dali::ShaderEffect::UniformCoordinateType > DerivedType;
170 // Reserve some memory inside the render queue
171 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
177 void Shader::ForwardGridDensity( BufferIndex updateBufferIndex, float density )
179 typedef MessageValue1< Shader, float > DerivedType;
181 // Reserve some memory inside the render queue
182 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
188 void Shader::ForwardHints( BufferIndex updateBufferIndex, Dali::ShaderEffect::GeometryHints hint )
190 typedef MessageValue1< Shader, Dali::ShaderEffect::GeometryHints > DerivedType;
192 // Reserve some memory inside the render queue
193 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
199 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 // The following methods are called during RenderManager::Render()
201 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
203 void Shader::SetTextureId( Integration::ResourceId textureId )
205 if ( mRenderTextureId != textureId )
207 mRenderTextureId = textureId;
212 Integration::ResourceId Shader::GetTextureIdToRender()
214 return mRenderTextureId;
217 void Shader::SetGridDensity( float density )
219 mGridDensity = density;
222 float Shader::GetGridDensity()
227 void Shader::InstallUniformMetaInRender( UniformMeta* meta )
229 mUniformMetadata.PushBack( meta );
232 void Shader::SetCoordinateTypeInRender( unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
234 DALI_ASSERT_DEBUG( index < mUniformMetadata.Count() );
235 mUniformMetadata[ index ]->SetCoordinateType( type );
238 void Shader::SetProgram( GeometryType geometryType,
239 ShaderSubTypes subType,
240 Integration::ResourceId resourceId,
241 Integration::ShaderDataPtr shaderData,
242 ProgramCache* programCache,
243 bool modifiesGeometry )
245 DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d %d\n", (int)geometryType, resourceId);
247 Program* program = Program::New( *programCache, shaderData, modifiesGeometry );
249 ShaderSubTypes theSubType = subType;
250 if( subType == SHADER_SUBTYPE_ALL )
252 theSubType = SHADER_DEFAULT;
255 const unsigned int geometryIndex = GetGeometryTypeIndex( geometryType );
256 if(subType == SHADER_SUBTYPE_ALL)
258 mPrograms[geometryIndex].Resize(1);
259 mPrograms[geometryIndex][theSubType] = program;
260 mPrograms[geometryIndex].mUseDefaultForAllSubtypes = true;
264 mPrograms[geometryIndex][theSubType] = program;
265 mPrograms[geometryIndex].mUseDefaultForAllSubtypes = false;
269 bool Shader::AreSubtypesRequired(GeometryType geometryType)
271 DALI_ASSERT_DEBUG(geometryType < GEOMETRY_TYPE_LAST);
272 unsigned int programType = GetGeometryTypeIndex( geometryType );
274 return ! mPrograms[ programType ].mUseDefaultForAllSubtypes;
277 Program* Shader::GetProgram( Context& context,
279 ShaderSubTypes subType,
280 unsigned int& programIndex )
282 DALI_ASSERT_DEBUG(type < GEOMETRY_TYPE_LAST);
283 DALI_DEBUG_OSTREAM(debugStream);
285 programIndex = GetGeometryTypeIndex( type );
287 DALI_ASSERT_DEBUG((unsigned int)subType < mPrograms[ programIndex ].Count());
289 return mPrograms[ programIndex ][ subType ];
293 void Shader::SetUniforms( Context& context,
295 BufferIndex bufferIndex,
296 unsigned int programIndex,
297 ShaderSubTypes subType )
299 DALI_ASSERT_DEBUG( programIndex < Log<GEOMETRY_TYPE_LAST>::value );
300 DALI_DEBUG_OSTREAM(debugStream);
302 if( mRenderTextureId && ( mTexture == NULL ) )
304 mTexture = mTextureCache->GetTexture( mRenderTextureId );
306 DALI_ASSERT_DEBUG( mTexture != NULL );
309 GLint loc = Program::UNIFORM_UNKNOWN;
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 )
317 // got effect texture, bind it to texture unit 1
318 mTextureCache->BindTexture( mTexture, mRenderTextureId, GL_TEXTURE_2D, TEXTURE_UNIT_SHADER);
320 // Apply the default sampling options for now
321 mTexture->ApplySampler( TEXTURE_UNIT_SHADER, ImageSampler::PackBitfield( FilterMode::DEFAULT, FilterMode::DEFAULT ) );
323 DALI_PRINT_UNIFORM( debugStream, bufferIndex, "sEffect", TEXTURE_UNIT_SHADER );
325 program.SetUniform1i( loc, TEXTURE_UNIT_SHADER );
329 // We should have one UniformMeta per uniform property
330 for ( unsigned int i = 0u; i < mUniformMetadata.Count(); ++i )
332 UniformMeta& metadata = *mUniformMetadata[i];
333 const PropertyBase& property = metadata.property;
335 // send the updated uniform to the program
336 if ( metadata.name.length() > 0 )
338 // 0 means program has not got a cache index for this uniform
339 if( 0 == metadata.cacheIndeces[ programIndex ][ subType ] )
341 // register cacheindex for this program
342 metadata.cacheIndeces[ programIndex ][ subType ] = program.RegisterUniform( metadata.name );
344 loc = program.GetUniformLocation( metadata.cacheIndeces[ programIndex ][ subType ] );
346 // if we find uniform with location
347 if ( Program::UNIFORM_UNKNOWN != loc )
349 DALI_PRINT_CUSTOM_UNIFORM( debugStream, bufferIndex, metadata.name, property );
351 // switch based on property type to use correct GL uniform setter
352 switch ( property.GetType() )
354 case Property::BOOLEAN :
356 program.SetUniform1i( loc, property.GetBoolean( bufferIndex ) );
359 case Property::INTEGER :
361 program.SetUniform1i( loc, property.GetInteger( bufferIndex ) );
364 case Property::UNSIGNED_INTEGER :
366 program.SetUniform1i( loc, property.GetUnsignedInteger( bufferIndex ) );
369 case Property::FLOAT :
371 program.SetUniform1f( loc, property.GetFloat( bufferIndex ) );
374 case Property::VECTOR2 :
376 Vector2 value( property.GetVector2( bufferIndex ) );
378 switch ( metadata.coordinateType )
380 case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION :
383 * Convert coordinates from viewport to GL view space
385 * Viewport coordinate
393 * GL view space coordinates
394 * (width/2,-height/2)
399 * (-width/2,height/2)
401 const Rect< int >& viewport = context.GetViewport();
402 value.x = viewport.width * 0.5f - value.x;
403 value.y = value.y - viewport.height * 0.5f;
407 case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION :
409 // Check diagram in COORDINATE_TYPE_VIEWPORT_POSITION
413 case Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT :
415 // nothing to do in this case
418 // no default so compiler will warn if a case is not handled
421 program.SetUniform2f( loc, value.x, value.y );
425 case Property::VECTOR3 :
427 Vector3 value( property.GetVector3( bufferIndex ) );
428 if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
433 program.SetUniform3f( loc, value.x, value.y, value.z );
437 case Property::VECTOR4 :
439 Vector4 value( property.GetVector4( bufferIndex ) );
440 if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
445 program.SetUniform4f( loc, value.x, value.y, value.z, value.w );
449 case Property::MATRIX:
451 const Matrix& value = property.GetMatrix(bufferIndex);
452 program.SetUniformMatrix4fv(loc, 1, value.AsFloat() );
456 case Property::MATRIX3:
458 const Matrix3& value = property.GetMatrix3(bufferIndex);
459 program.SetUniformMatrix3fv(loc, 1, value.AsFloat() );
464 case Property::ROTATION:
465 case Property::STRING:
466 case Property::RECTANGLE:
468 case Property::ARRAY:
469 case Property::TYPE_COUNT:
471 DALI_ASSERT_ALWAYS( 0 && "Invalid property type for a uniform" );
479 DALI_PRINT_SHADER_UNIFORMS(debugStream);
485 void SetTextureIdMessage( EventThreadServices& eventThreadServices, const Shader& shader, Integration::ResourceId textureId )
487 typedef MessageDoubleBuffered1< Shader, Integration::ResourceId > LocalType;
489 // Reserve some memory inside the message queue
490 unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
492 // Construct message in the message queue memory; note that delete should not be called on the return value
493 new (slot) LocalType( &shader, &Shader::ForwardTextureId, textureId );
496 void SetGridDensityMessage( EventThreadServices& eventThreadServices, const Shader& shader, float density )
498 typedef MessageDoubleBuffered1< Shader, float > LocalType;
500 // Reserve some memory inside the message queue
501 unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
503 // Construct message in the message queue memory; note that delete should not be called on the return value
504 new (slot) LocalType( &shader, &Shader::ForwardGridDensity, density );
507 void SetHintsMessage( EventThreadServices& eventThreadServices, const Shader& shader, Dali::ShaderEffect::GeometryHints hint )
509 typedef MessageDoubleBuffered1< Shader, Dali::ShaderEffect::GeometryHints > LocalType;
511 // Reserve some memory inside the message queue
512 unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
514 // Construct message in the message queue memory; note that delete should not be called on the return value
515 new (slot) LocalType( &shader, &Shader::ForwardHints, hint );
518 void InstallUniformMetaMessage( EventThreadServices& eventThreadServices, const Shader& shader, UniformMeta& meta )
520 typedef MessageDoubleBuffered1< Shader, UniformMeta* > LocalType;
522 // Reserve some memory inside the message queue
523 unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
525 // Construct message in the message queue memory; note that delete should not be called on the return value
526 new (slot) LocalType( &shader, &Shader::ForwardUniformMeta, &meta );
529 void SetCoordinateTypeMessage( EventThreadServices& eventThreadServices, const Shader& shader, unsigned int index, Dali::ShaderEffect::UniformCoordinateType type )
531 typedef MessageDoubleBuffered2< Shader, unsigned int, Dali::ShaderEffect::UniformCoordinateType > LocalType;
533 // Reserve some memory inside the message queue
534 unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
536 // Construct message in the message queue memory; note that delete should not be called on the return value
537 new (slot) LocalType( &shader, &Shader::ForwardCoordinateType, index, type );
541 } // namespace SceneGraph
543 } // namespace Internal