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/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>
38 #ifdef DALI_PRINT_RENDER_INFO
41 #define DALI_DEBUG_OSTREAM(streamName) std::stringstream streamName;
43 #define DALI_PRINT_UNIFORM(streamName,bufferIndex,name,value) \
45 streamName << " " << name << ": " << value; \
48 #define DALI_PRINT_CUSTOM_UNIFORM(streamName,bufferIndex,name,property) \
50 streamName << " " << name << ": "; \
51 property.DebugPrint( streamName, bufferIndex ); \
54 #define DALI_PRINT_SHADER_UNIFORMS(streamName) \
56 std::string debugString( streamName.str() ); \
57 DALI_LOG_RENDER_INFO( " %s\n", debugString.c_str() ); \
60 #else // DALI_PRINT_RENDER_INFO
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)
67 #endif // DALI_PRINT_RENDER_INFO
78 namespace // unnamed namespace
81 // Convert Geometry type bitmask to an array index
82 unsigned int GetGeometryTypeIndex(GeometryType type)
84 unsigned int index = Log<GEOMETRY_TYPE_IMAGE>::value;
85 if ( type & GEOMETRY_TYPE_IMAGE )
87 index = Log<GEOMETRY_TYPE_IMAGE>::value;
89 else if ( type & GEOMETRY_TYPE_TEXT )
91 index = Log<GEOMETRY_TYPE_TEXT>::value;
93 else if ( type & GEOMETRY_TYPE_MESH )
95 index = Log<GEOMETRY_TYPE_MESH>::value;
97 else if ( type & GEOMETRY_TYPE_TEXTURED_MESH )
99 index = Log<GEOMETRY_TYPE_TEXTURED_MESH>::value;
104 } // unnamed namespace
109 Shader::Shader( Dali::ShaderEffect::GeometryHints& hints )
110 : mGeometryHints( hints ),
111 mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
113 mRenderTextureId( 0 ),
114 mUpdateTextureId( 0 ),
116 mPostProcessDispatcher(NULL),
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)
123 mPrograms[ i ].Resize(SHADER_SUBTYPE_LAST);
131 void Shader::Initialize( PostProcessResourceDispatcher& postProcessDispatcher, RenderQueue& renderQueue, TextureCache& textureCache )
133 mPostProcessDispatcher = &postProcessDispatcher;
134 mRenderQueue = &renderQueue;
135 mTextureCache = &textureCache;
138 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 // The following methods are called during UpdateManager::Update()
140 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 void Shader::ForwardTextureId( BufferIndex updateBufferIndex, ResourceId textureId )
144 mUpdateTextureId = textureId;
146 typedef MessageValue1< Shader, Integration::ResourceId > DerivedType;
148 // Reserve some memory inside the render queue
149 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
155 Integration::ResourceId Shader::GetEffectTextureResourceId()
157 return mUpdateTextureId;
160 void Shader::ForwardUniformMeta( BufferIndex updateBufferIndex, UniformMeta* meta )
162 // Defer setting uniform metadata until the next Render
163 // (Maintains thread safety on std::vector)
165 typedef MessageValue1< Shader, UniformMeta* > DerivedType;
167 // Reserve some memory inside the render queue
168 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
174 void Shader::ForwardGridDensity( BufferIndex updateBufferIndex, float density )
176 typedef MessageValue1< Shader, float > DerivedType;
178 // Reserve some memory inside the render queue
179 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
185 void Shader::ForwardHints( BufferIndex updateBufferIndex, Dali::ShaderEffect::GeometryHints hint )
187 typedef MessageValue1< Shader, Dali::ShaderEffect::GeometryHints > DerivedType;
189 // Reserve some memory inside the render queue
190 unsigned int* slot = mRenderQueue->ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
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 );
196 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
197 // The following methods are called during RenderManager::Render()
198 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 void Shader::SetTextureId( Integration::ResourceId textureId )
202 if ( mRenderTextureId != textureId )
204 mRenderTextureId = textureId;
209 Integration::ResourceId Shader::GetTextureIdToRender()
211 return mRenderTextureId;
214 void Shader::SetGridDensity( float density )
216 mGridDensity = density;
219 float Shader::GetGridDensity()
224 void Shader::InstallUniformMetaInRender( UniformMeta* meta )
226 mUniformMetadata.PushBack( meta );
229 void Shader::SetProgram( GeometryType geometryType,
230 ShaderSubTypes subType,
231 Integration::ResourceId resourceId,
232 Integration::ShaderDataPtr shaderData,
234 bool modifiesGeometry )
236 DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d %d\n", (int)geometryType, resourceId);
238 bool precompiledBinary = shaderData->HasBinary();
240 Program* program = Program::New( resourceId, shaderData.Get(), *context, modifiesGeometry );
242 ShaderSubTypes theSubType = subType;
243 if( subType == SHADER_SUBTYPE_ALL )
245 theSubType = SHADER_DEFAULT;
248 if(geometryType != GEOMETRY_TYPE_TEXT && subType == SHADER_SUBTYPE_ALL)
250 mPrograms[GetGeometryTypeIndex(geometryType)].Resize(1);
251 mPrograms[GetGeometryTypeIndex(geometryType)][theSubType] = program;
252 mPrograms[GetGeometryTypeIndex(geometryType)].mUseDefaultForAllSubtypes = true;
256 mPrograms[GetGeometryTypeIndex(geometryType)][theSubType] = program;
257 mPrograms[GetGeometryTypeIndex(geometryType)].mUseDefaultForAllSubtypes = false;
260 if( !precompiledBinary )
262 // The binary will have been compiled/linked during Program::New(), so save it
263 if( shaderData->HasBinary() )
265 DALI_ASSERT_DEBUG( mPostProcessDispatcher != NULL );
266 ResourcePostProcessRequest request( resourceId, ResourcePostProcessRequest::SAVE );
267 mPostProcessDispatcher->DispatchPostProcessRequest( request );
272 bool Shader::AreSubtypesRequired(GeometryType geometryType)
274 DALI_ASSERT_DEBUG(geometryType < GEOMETRY_TYPE_LAST);
275 unsigned int programType = GetGeometryTypeIndex( geometryType );
277 return ! mPrograms[ programType ].mUseDefaultForAllSubtypes;
280 Program& Shader::GetProgram( Context& context,
282 ShaderSubTypes subType,
283 unsigned int& programIndex )
285 DALI_ASSERT_DEBUG(type < GEOMETRY_TYPE_LAST);
286 DALI_DEBUG_OSTREAM(debugStream);
288 programIndex = GetGeometryTypeIndex( type );
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 ]);
294 Program& program = *(mPrograms[ programIndex ][ subType ]);
299 void Shader::SetUniforms( Context& context,
301 BufferIndex bufferIndex,
302 unsigned int programIndex,
303 ShaderSubTypes subType )
305 DALI_ASSERT_DEBUG( programIndex < Log<GEOMETRY_TYPE_LAST>::value );
306 DALI_DEBUG_OSTREAM(debugStream);
308 if( mRenderTextureId && ( mTexture == NULL ) )
310 mTexture = mTextureCache->GetTexture( mRenderTextureId );
312 DALI_ASSERT_DEBUG( mTexture != NULL );
315 GLint loc = Program::UNIFORM_UNKNOWN;
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() );
324 // get effect sampler uniform
325 const GLint loc = program.GetUniformLocation( Program::UNIFORM_EFFECT_SAMPLER );
326 if( Program::UNIFORM_UNKNOWN != loc )
328 DALI_PRINT_UNIFORM( debugStream, bufferIndex, "sEffect", 1 );
330 program.SetUniform1i( loc, 1 );
334 // We should have one UniformMeta per uniform property
335 for ( unsigned int i = 0u; i < mUniformMetadata.Count(); ++i )
337 UniformMeta& metadata = *mUniformMetadata[i];
338 const PropertyBase& property = metadata.property;
340 // send the updated uniform to the program
341 if ( metadata.name.length() > 0 )
343 // 0 means program has not got a cache index for this uniform
344 if( 0 == metadata.cacheIndeces[ programIndex ][ subType ] )
346 // register cacheindex for this program
347 metadata.cacheIndeces[ programIndex ][ subType ] = program.RegisterUniform( metadata.name );
349 loc = program.GetUniformLocation( metadata.cacheIndeces[ programIndex ][ subType ] );
351 // if we find uniform with location
352 if ( Program::UNIFORM_UNKNOWN != loc )
354 DALI_PRINT_CUSTOM_UNIFORM( debugStream, bufferIndex, metadata.name, property );
356 // switch based on property type to use correct GL uniform setter
357 switch ( property.GetType() )
359 case Property::FLOAT :
361 program.SetUniform1f( loc, property.GetFloat( bufferIndex ) );
364 case Property::INTEGER :
366 program.SetUniform1i( loc, property.GetInteger( bufferIndex ) );
369 case Property::VECTOR2 :
371 Vector2 value( property.GetVector2( bufferIndex ) );
373 switch ( metadata.coordinateType )
375 case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION :
378 * Convert coordinates from viewport to GL view space
380 * Viewport coordinate
388 * GL view space coordinates
389 * (width/2,-height/2)
394 * (-width/2,height/2)
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;
402 case Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION :
404 // Check diagram in COORDINATE_TYPE_VIEWPORT_POSITION
408 case Dali::ShaderEffect::COORDINATE_TYPE_TEXTURE_POSITION :
413 mTexture->GetTextureCoordinates( textureArea );
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;
423 case Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT :
425 // nothing to do in this case
428 // no default so compiler will warn if a case is not handled
431 program.SetUniform2f( loc, value.x, value.y );
435 case Property::VECTOR3 :
437 Vector3 value( property.GetVector3( bufferIndex ) );
438 if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
443 program.SetUniform3f( loc, value.x, value.y, value.z );
447 case Property::VECTOR4 :
449 Vector4 value( property.GetVector4( bufferIndex ) );
450 if( Dali::ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION == metadata.coordinateType)
455 program.SetUniform4f( loc, value.x, value.y, value.z, value.w );
459 case Property::MATRIX:
461 const Matrix& value = property.GetMatrix(bufferIndex);
462 program.SetUniformMatrix4fv(loc, 1, value.AsFloat() );
466 case Property::MATRIX3:
468 const Matrix3& value = property.GetMatrix3(bufferIndex);
469 program.SetUniformMatrix3fv(loc, 1, value.AsFloat() );
475 // Only float and Vector properties are passed as uniforms; other types are ignored.
483 DALI_PRINT_SHADER_UNIFORMS(debugStream);
486 } // namespace SceneGraph
488 } // namespace Internal