2 * Copyright (c) 2016 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/update/manager/geometry-batcher.h>
22 #include <dali/internal/render/common/render-item.h>
23 #include <dali/internal/render/common/render-tracker.h>
24 #include <dali/internal/render/common/render-instruction.h>
25 #include <dali/internal/render/common/render-instruction-container.h>
26 #include <dali/internal/render/shaders/scene-graph-shader.h>
27 #include <dali/internal/render/renderers/render-renderer.h>
28 #include <dali/internal/render/renderers/render-property-buffer.h>
29 #include <dali/internal/render/renderers/render-geometry.h>
30 #include <dali/internal/update/rendering/scene-graph-renderer.h>
31 #include <dali/internal/update/controllers/scene-controller.h>
32 #include <dali/internal/update/manager/update-manager.h>
33 #include <dali/internal/common/math.h>
38 // helper macros to deal with handles
39 #define BATCH_LOCAL_INDEX(x) (x&0xFFFF)
40 #define BATCH_PARENT_INDEX(x) ((x>>16)&0xFFFF)
41 #define BATCH_INDEX_CREATE( batchParentIndex, batchIndex ) ( ( ( (batchParentIndex)&0xFFFF ) << 16 ) | ( (batchIndex)&0xFFFF ) )
44 * The TransformVertexBufferInfo struct
45 * Must be filled before transforming vertices
47 struct TransformVertexBufferData
49 void* destinationPtr; ///< pointer to the destination vertex buffer
50 const void* sourcePtr; ///< pointer to the source vertex buffer
51 float* transform; ///< transform relative to batch parent
52 const float* worldMatrix; ///< model/world matrix of node being batched
53 const float* parentInvWorldMatrix; ///< inv world matrix of batch parent
54 unsigned componentSize; ///< size of component
55 unsigned vertexCount; ///< number of vertices to process
56 const float* size; ///< size of render item
60 * @brief function transforms vertices from 'source' and writes into 'destination'
61 * @param[in,out] data Filled TransformVertexBufferInfo arguments structure
63 template <typename PositionType >
64 void TransformVertexBuffer( TransformVertexBufferData& data )
66 const PositionType* source = reinterpret_cast<const PositionType*>( data.sourcePtr );
67 PositionType* destination = reinterpret_cast<PositionType*>( data.destinationPtr );
69 size_t componentSize = data.componentSize ? data.componentSize : sizeof( PositionType );
70 const void* sourceEnd = (reinterpret_cast<const char*>( source ) + ( data.vertexCount*componentSize ));
71 for( ; source < sourceEnd;
72 *(reinterpret_cast<char**>( &destination )) += componentSize,
73 *(reinterpret_cast<const char**>( &source )) += componentSize
76 Dali::Internal::MultiplyVectorBySize( *destination, *source, data.size );
77 Dali::Internal::MultiplyVectorByMatrix4( *destination, data.transform, *destination );
93 * @brief The VertexDescriptor struct
94 * Holds details of vertex format used for batching
96 struct VertexDescriptor
99 : mVertexComponentSize( 0 ),
100 mVertexPositionType( Dali::Property::NONE ),
101 mVertexFormat( NULL )
105 unsigned int mVertexComponentSize; ///< Vertex component size in bytes
106 Dali::Property::Type mVertexPositionType; ///< Vertex position type ( may be Vector2, Vector3, Vector4 )
107 Dali::Internal::Render::PropertyBuffer::Format* mVertexFormat; ///< Vertex format cloned from the very first batched item
113 : batchParentNode( NULL ),
124 BatchKey( Node* node )
126 MakeFromNode( node );
129 inline void MakeFromNode( Node* node )
131 Renderer* renderer = node->GetRendererAt( 0 );
132 batchParentNode = node->GetBatchParent();
133 shader = &renderer->GetShader();
134 textureSet = renderer->GetTextures();
135 depthIndex = renderer->GetDepthIndex();
138 inline bool operator==( const BatchKey& key )
140 return batchParentNode == key.batchParentNode && shader == key.shader && textureSet == key.textureSet && depthIndex == key.depthIndex;
143 inline bool operator!=( const BatchKey& key )
145 return !( *this == key );
148 const Node* batchParentNode; /// batch parent node that owns batch
149 const Shader* shader; /// shader associated with the batch
150 const TextureSet* textureSet; /// texture set used by the batch
151 int depthIndex; /// depth index of the batch
155 * @brief The Batch struct
156 * Stores details of single batch
160 Batch( const BatchKey& key, Render::Geometry* batchGeometry = NULL )
162 geometry( batchGeometry ),
168 BatchKey batchKey; /// Unique batch key
169 Vector<unsigned short> indices; /// index buffer per batch
170 Render::Geometry* geometry; /// Batch geometry
171 size_t renderedFrame; /// Flag used to determine if batch has already rendered during a frame
172 bool dirty; /// 'dirty' flag per batch
175 typedef std::vector<Batch> BatchList;
178 * @brief The BatchParent struct
179 * Stores list of children of single batch parent
183 Node* node; /// Pointer to a node which is a parent for batch(es)
184 Vector<Node*> batchedChildren; /// List of batchable children
185 BatchList batches; /// List of batches which belong to this parent
186 Render::PropertyBuffer* vertexBuffer; /// Vertex buffer shared by all batches for this parent
187 bool needsUpdate; /// Flag indicating if batches should be updated
196 int GetBatchKeyIndex( size_t batchParentIndex, const BatchKey& key )
198 BatchParent& batchParent = batchParents[ batchParentIndex ];
199 for( size_t j = 0; j < batchParent.batches.size(); ++j )
201 if( batchParent.batches[j].batchKey == key )
203 return BATCH_INDEX_CREATE( batchParentIndex, j );
209 std::vector<BatchParent> batchParents; /// non-trivial type, hence std::vector
210 UpdateManager* updateManager;
214 GeometryBatcher::GeometryBatcher() :
220 void GeometryBatcher::SetUpdateManager( UpdateManager* updateManager )
222 mImpl->updateManager = updateManager;
225 GeometryBatcher::~GeometryBatcher()
230 bool GeometryBatcher::CloneVertexFormat( const Render::Geometry* sourceGeometry, VertexDescriptor& vertexDescriptor )
232 const Render::Geometry* geometry = sourceGeometry;
233 const Render::PropertyBuffer::Format* format = geometry->GetPropertyBuffer( 0 )->GetFormat();
240 Render::PropertyBuffer::Format* clonedVertexFormat = new Render::PropertyBuffer::Format( *format );
241 Render::PropertyBuffer::Component& firstComponent = clonedVertexFormat->components[0];
243 vertexDescriptor.mVertexPositionType = firstComponent.type;
244 vertexDescriptor.mVertexComponentSize = clonedVertexFormat->size;
245 vertexDescriptor.mVertexFormat = clonedVertexFormat;
250 void GeometryBatcher::Update( BufferIndex bufferIndex )
252 if( !mImpl->batchParents.empty() )
254 std::vector<BatchParent>::iterator iter = mImpl->batchParents.begin();
255 std::vector<BatchParent>::iterator end = mImpl->batchParents.end();
257 // for each Batch Parent
258 for( size_t batchParentIndex = 0; iter != end; ++iter, ++batchParentIndex )
260 BatchParent& batchParentData = *iter;
261 // Skip update if batch parent doesn't need it
262 if( !batchParentData.needsUpdate )
267 Node* batchParentNode = batchParentData.node;
269 // Skip if batch parent doesn't have batched children
270 size_t size = batchParentData.batchedChildren.Size();
273 batchParentData.needsUpdate = false;
277 bool batchingFailed( false );
278 uint32_t batchKeyIndex( BATCH_NULL_HANDLE );
282 VertexDescriptor vertexDescriptor;
284 // Destination vertex buffer per batch parent
285 Vector<char>& vertexBufferDest = *( new Vector<char>() );
286 Render::PropertyBuffer* batchVertexBuffer = new Render::PropertyBuffer();
288 size_t currentElementIndex = 0;
290 Matrix invWorldMatrix( batchParentNode->GetWorldMatrix( bufferIndex ) );
291 invWorldMatrix.Invert();
293 // For each batched child of this batch parent...
294 for( size_t i = 0; i < size; ++i )
296 Node* node = batchParentData.batchedChildren[i];
298 const SceneGraph::Renderer* renderer = node->GetRendererAt( 0 );
301 const Render::Geometry* geometry = &renderer->GetGeometry();
303 // Generate batch key
304 key.MakeFromNode( node );
306 // format of first property buffer
307 const Render::PropertyBuffer* vertexBuffer = geometry->GetPropertyBuffer( 0 );
309 // Geometry of the node may not be ready, in that case we discard whole batch
310 if( !vertexBuffer || ( !vertexDescriptor.mVertexFormat && !CloneVertexFormat( geometry, vertexDescriptor ) ) )
312 batchingFailed = true;
316 // Instantiate new batch
320 batchKeyIndex = mImpl->GetBatchKeyIndex( batchParentIndex, key );
322 if( batchKeyIndex == BATCH_NULL_HANDLE )
324 // Create new batch geometry
325 Render::Geometry* newGeometry = new Render::Geometry();
327 Batch batch( key, newGeometry );
330 batchParentData.batches.push_back( batch );
333 batchKeyIndex = BATCH_INDEX_CREATE( batchParentIndex, batchParentData.batches.size()-1 );
335 // Vertex buffer may be set before it's filled with data
336 newGeometry->AddPropertyBuffer( batchVertexBuffer );
338 // Register geometry with update manager
339 mImpl->updateManager->AddGeometry( newGeometry );
343 // Tell node which batch it belongs to
344 node->mBatchIndex = batchKeyIndex;
346 uint32_t localIndex = BATCH_LOCAL_INDEX( batchKeyIndex );
348 if( !batchParentData.batches[ localIndex ].dirty )
353 const uint32_t vertexBufferSize = vertexBuffer->GetDataSize();
354 const char* vertexDataSource = &vertexBuffer->GetData()[ 0 ];
356 uint32_t currentSize = vertexBufferDest.Size();
357 vertexBufferDest.Resize( currentSize + vertexBufferSize );
358 char* vertexDataDest = &vertexBufferDest[ currentSize ];
360 // copy data as they are
361 std::copy( vertexDataSource, vertexDataSource + vertexBufferSize, vertexDataDest );
364 const Matrix& worldMatrix = node->GetWorldMatrix( bufferIndex );
367 const unsigned int sourceVertexCount = vertexBufferSize / vertexDescriptor.mVertexComponentSize;
369 // compute transform for the node
370 TransformVertexBufferData transformParameters;
371 transformParameters.destinationPtr = vertexDataDest;
372 transformParameters.sourcePtr = vertexDataSource;
374 // perform transformation
375 Matrix transformMatrix;
376 Dali::Internal::MultiplyMatrices( transformMatrix.AsFloat(), worldMatrix.AsFloat(), invWorldMatrix.AsFloat() );
377 transformParameters.transform = transformMatrix.AsFloat();
378 transformParameters.componentSize = vertexDescriptor.mVertexComponentSize;
379 transformParameters.vertexCount = sourceVertexCount;
380 transformParameters.size = node->GetSize( bufferIndex ).AsFloat();
382 // Perform vertex transform based on the vertex format
383 switch( vertexDescriptor.mVertexPositionType )
385 case Dali::Property::VECTOR2:
387 TransformVertexBuffer<Vec2>( transformParameters );
390 case Dali::Property::VECTOR3:
392 TransformVertexBuffer<Vec3>( transformParameters );
395 case Dali::Property::VECTOR4:
397 TransformVertexBuffer<Vec4>( transformParameters );
402 DALI_ASSERT_ALWAYS( true && "Incorrect vertex format! Use Vector2, Vector3 or Vector4 as position!" );
406 // update index buffer
407 Batch& batch = batchParentData.batches[ localIndex ];
408 uint32_t currentIndexOffset = batch.indices.Size();
409 batch.indices.Resize( batch.indices.Size() + sourceVertexCount );
410 for( size_t k = 0; k < sourceVertexCount; ++k )
412 size_t index = currentElementIndex + k;
413 batch.indices[k + currentIndexOffset] = (unsigned short)index;
416 currentElementIndex += sourceVertexCount;
421 delete &vertexBufferDest;
422 delete batchVertexBuffer;
426 // Add shared property buffer
427 mImpl->updateManager->AddPropertyBuffer( batchVertexBuffer );
428 batchVertexBuffer->SetFormat( vertexDescriptor.mVertexFormat );
429 batchVertexBuffer->SetData( &vertexBufferDest, vertexBufferDest.Size()/vertexDescriptor.mVertexComponentSize );
431 batchParentData.needsUpdate = false;
432 batchParentData.vertexBuffer = batchVertexBuffer;
434 // Update index buffers for all batches own by that batch parent
435 std::vector<Batch>::iterator iter = batchParentData.batches.begin();
436 std::vector<Batch>::iterator end = batchParentData.batches.end();
437 for( ; iter != end; ++iter )
439 Batch& batch = (*iter);
440 batch.geometry->SetIndexBuffer( batch.indices );
445 ++mImpl->currentFrame;
448 void GeometryBatcher::AddBatchParent( Node* node )
450 BatchParent batchParent;
451 batchParent.node = node;
452 batchParent.needsUpdate = true;
453 batchParent.batchedChildren.Clear();
455 mImpl->batchParents.push_back( batchParent );
458 void GeometryBatcher::RemoveBatchParent( Node* node )
460 for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
462 BatchParent& batchParent = mImpl->batchParents[i];
463 if( node == batchParent.node )
465 // tell children they're not batched anymore
466 Vector<Node*>::Iterator iter = batchParent.batchedChildren.Begin();
467 Vector<Node*>::Iterator end = batchParent.batchedChildren.End();
468 for( ; iter != end; ++iter )
471 child->mBatchIndex = BATCH_NULL_HANDLE;
474 // delete all resources that belongs to the batch parent
475 for( size_t j = 0; j < batchParent.batches.size(); ++j )
477 Batch& batch = batchParent.batches[j];
478 mImpl->updateManager->RemoveGeometry( batch.geometry );
481 // delete main vertex buffer
482 mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
489 void GeometryBatcher::AddNode( Node* node )
491 // look for batch parent
492 Node* currentNode = node->GetParent();
493 Node* batchParent = NULL;
496 if( currentNode->mIsBatchParent )
498 batchParent = currentNode;
500 currentNode = currentNode->GetParent();
506 for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
508 if( mImpl->batchParents[i].node == batchParent )
510 mImpl->batchParents[i].batchedChildren.PushBack( node );
511 node->SetBatchParent( batchParent );
512 mImpl->batchParents[i].needsUpdate = true;
519 void GeometryBatcher::RemoveNode( Node* node )
521 if( node->mBatchIndex == BATCH_NULL_HANDLE )
526 uint32_t parentIndex = BATCH_PARENT_INDEX( node->mBatchIndex );
528 BatchParent& batchParent = mImpl->batchParents[ parentIndex ];
530 // delete all batches from batch parent
531 for( size_t i = 0; i < batchParent.batches.size(); ++i )
533 Batch& batch = batchParent.batches[ i ];
536 mImpl->updateManager->RemoveGeometry( batch.geometry );
539 batchParent.batches.clear();
541 // for all children reset batch index to BATCH_NULL_HANDLE
542 for( size_t i = 0; i < batchParent.batchedChildren.Size(); )
544 Node* child = batchParent.batchedChildren[i];
548 batchParent.batchedChildren.Erase( batchParent.batchedChildren.Begin() + i );
552 child->mBatchIndex = BATCH_NULL_HANDLE;
557 mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
558 batchParent.needsUpdate = true;
561 bool GeometryBatcher::HasRendered( uint32_t batchIndex )
563 return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame == mImpl->currentFrame;
566 void GeometryBatcher::SetRendered( uint32_t batchIndex )
568 mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame = mImpl->currentFrame;
571 Render::Geometry* GeometryBatcher::GetGeometry( uint32_t batchIndex )
573 return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].geometry;
576 } // namespace SceneGraph
578 } // namespace Internal