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
194 updateManager( NULL ),
199 int GetBatchKeyIndex( size_t batchParentIndex, const BatchKey& key )
201 BatchParent& batchParent = batchParents[ batchParentIndex ];
202 for( size_t j = 0; j < batchParent.batches.size(); ++j )
204 if( batchParent.batches[j].batchKey == key )
206 return BATCH_INDEX_CREATE( batchParentIndex, j );
212 std::vector<BatchParent> batchParents; /// non-trivial type, hence std::vector
213 UpdateManager* updateManager;
217 GeometryBatcher::GeometryBatcher() :
223 void GeometryBatcher::SetUpdateManager( UpdateManager* updateManager )
225 mImpl->updateManager = updateManager;
228 GeometryBatcher::~GeometryBatcher()
233 bool GeometryBatcher::CloneVertexFormat( const Render::Geometry* sourceGeometry, VertexDescriptor& vertexDescriptor )
235 const Render::Geometry* geometry = sourceGeometry;
236 const Render::PropertyBuffer::Format* format = geometry->GetPropertyBuffer( 0 )->GetFormat();
243 Render::PropertyBuffer::Format* clonedVertexFormat = new Render::PropertyBuffer::Format( *format );
244 Render::PropertyBuffer::Component& firstComponent = clonedVertexFormat->components[0];
246 vertexDescriptor.mVertexPositionType = firstComponent.type;
247 vertexDescriptor.mVertexComponentSize = clonedVertexFormat->size;
248 vertexDescriptor.mVertexFormat = clonedVertexFormat;
253 void GeometryBatcher::Update( BufferIndex bufferIndex )
255 if( !mImpl->batchParents.empty() )
257 std::vector<BatchParent>::iterator iter = mImpl->batchParents.begin();
258 std::vector<BatchParent>::iterator end = mImpl->batchParents.end();
260 // for each Batch Parent
261 for( size_t batchParentIndex = 0; iter != end; ++iter, ++batchParentIndex )
263 BatchParent& batchParentData = *iter;
264 // Skip update if batch parent doesn't need it
265 if( !batchParentData.needsUpdate )
270 Node* batchParentNode = batchParentData.node;
272 // Skip if batch parent doesn't have batched children
273 size_t size = batchParentData.batchedChildren.Size();
276 batchParentData.needsUpdate = false;
280 bool batchingFailed( false );
281 uint32_t batchKeyIndex( BATCH_NULL_HANDLE );
285 VertexDescriptor vertexDescriptor;
287 // Destination vertex buffer per batch parent
288 Vector<char>& vertexBufferDest = *( new Vector<char>() );
289 Render::PropertyBuffer* batchVertexBuffer = new Render::PropertyBuffer();
291 size_t currentElementIndex = 0;
293 Matrix invWorldMatrix( batchParentNode->GetWorldMatrix( bufferIndex ) );
294 invWorldMatrix.Invert();
296 // For each batched child of this batch parent...
297 for( size_t i = 0; i < size; ++i )
299 Node* node = batchParentData.batchedChildren[i];
301 const SceneGraph::Renderer* renderer = node->GetRendererAt( 0 );
304 const Render::Geometry* geometry = &renderer->GetGeometry();
306 // Generate batch key
307 key.MakeFromNode( node );
309 // format of first property buffer
310 const Render::PropertyBuffer* vertexBuffer = geometry->GetPropertyBuffer( 0 );
312 // Geometry of the node may not be ready, in that case we discard whole batch
313 if( !vertexBuffer || ( !vertexDescriptor.mVertexFormat && !CloneVertexFormat( geometry, vertexDescriptor ) ) )
315 batchingFailed = true;
319 // Instantiate new batch
323 batchKeyIndex = mImpl->GetBatchKeyIndex( batchParentIndex, key );
325 if( batchKeyIndex == BATCH_NULL_HANDLE )
327 // Create new batch geometry
328 Render::Geometry* newGeometry = new Render::Geometry();
330 Batch batch( key, newGeometry );
333 batchParentData.batches.push_back( batch );
336 batchKeyIndex = BATCH_INDEX_CREATE( batchParentIndex, batchParentData.batches.size()-1 );
338 // Vertex buffer may be set before it's filled with data
339 newGeometry->AddPropertyBuffer( batchVertexBuffer );
341 // Register geometry with update manager
342 mImpl->updateManager->AddGeometry( newGeometry );
346 // Tell node which batch it belongs to
347 node->mBatchIndex = batchKeyIndex;
349 uint32_t localIndex = BATCH_LOCAL_INDEX( batchKeyIndex );
351 if( !batchParentData.batches[ localIndex ].dirty )
356 const uint32_t vertexBufferSize = vertexBuffer->GetDataSize();
357 const char* vertexDataSource = &vertexBuffer->GetData()[ 0 ];
359 uint32_t currentSize = vertexBufferDest.Size();
360 vertexBufferDest.Resize( currentSize + vertexBufferSize );
361 char* vertexDataDest = &vertexBufferDest[ currentSize ];
363 // copy data as they are
364 std::copy( vertexDataSource, vertexDataSource + vertexBufferSize, vertexDataDest );
367 const Matrix& worldMatrix = node->GetWorldMatrix( bufferIndex );
370 const unsigned int sourceVertexCount = vertexBufferSize / vertexDescriptor.mVertexComponentSize;
372 // compute transform for the node
373 TransformVertexBufferData transformParameters;
374 transformParameters.destinationPtr = vertexDataDest;
375 transformParameters.sourcePtr = vertexDataSource;
377 // perform transformation
378 Matrix transformMatrix;
379 Dali::Internal::MultiplyMatrices( transformMatrix.AsFloat(), worldMatrix.AsFloat(), invWorldMatrix.AsFloat() );
380 transformParameters.transform = transformMatrix.AsFloat();
381 transformParameters.componentSize = vertexDescriptor.mVertexComponentSize;
382 transformParameters.vertexCount = sourceVertexCount;
383 transformParameters.size = node->GetSize( bufferIndex ).AsFloat();
385 // Perform vertex transform based on the vertex format
386 switch( vertexDescriptor.mVertexPositionType )
388 case Dali::Property::VECTOR2:
390 TransformVertexBuffer<Vec2>( transformParameters );
393 case Dali::Property::VECTOR3:
395 TransformVertexBuffer<Vec3>( transformParameters );
398 case Dali::Property::VECTOR4:
400 TransformVertexBuffer<Vec4>( transformParameters );
405 DALI_ASSERT_ALWAYS( true && "Incorrect vertex format! Use Vector2, Vector3 or Vector4 as position!" );
409 // update index buffer
410 Batch& batch = batchParentData.batches[ localIndex ];
411 uint32_t currentIndexOffset = batch.indices.Size();
412 batch.indices.Resize( batch.indices.Size() + sourceVertexCount );
413 for( size_t k = 0; k < sourceVertexCount; ++k )
415 size_t index = currentElementIndex + k;
416 batch.indices[k + currentIndexOffset] = (unsigned short)index;
419 currentElementIndex += sourceVertexCount;
424 delete &vertexBufferDest;
425 delete batchVertexBuffer;
429 // Add shared property buffer
430 mImpl->updateManager->AddPropertyBuffer( batchVertexBuffer );
431 batchVertexBuffer->SetFormat( vertexDescriptor.mVertexFormat );
432 batchVertexBuffer->SetData( &vertexBufferDest, vertexBufferDest.Size()/vertexDescriptor.mVertexComponentSize );
434 batchParentData.needsUpdate = false;
435 batchParentData.vertexBuffer = batchVertexBuffer;
437 // Update index buffers for all batches own by that batch parent
438 std::vector<Batch>::iterator iter = batchParentData.batches.begin();
439 std::vector<Batch>::iterator end = batchParentData.batches.end();
440 for( ; iter != end; ++iter )
442 Batch& batch = (*iter);
443 batch.geometry->SetIndexBuffer( batch.indices );
448 ++mImpl->currentFrame;
451 void GeometryBatcher::AddBatchParent( Node* node )
453 BatchParent batchParent;
454 batchParent.node = node;
455 batchParent.needsUpdate = true;
456 batchParent.batchedChildren.Clear();
458 mImpl->batchParents.push_back( batchParent );
461 void GeometryBatcher::RemoveBatchParent( Node* node )
463 for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
465 BatchParent& batchParent = mImpl->batchParents[i];
466 if( node == batchParent.node )
468 // tell children they're not batched anymore
469 Vector<Node*>::Iterator iter = batchParent.batchedChildren.Begin();
470 Vector<Node*>::Iterator end = batchParent.batchedChildren.End();
471 for( ; iter != end; ++iter )
474 child->mBatchIndex = BATCH_NULL_HANDLE;
477 // delete all resources that belongs to the batch parent
478 for( size_t j = 0; j < batchParent.batches.size(); ++j )
480 Batch& batch = batchParent.batches[j];
481 mImpl->updateManager->RemoveGeometry( batch.geometry );
484 // delete main vertex buffer
485 mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
492 void GeometryBatcher::AddNode( Node* node )
494 // look for batch parent
495 Node* currentNode = node->GetParent();
496 Node* batchParent = NULL;
499 if( currentNode->mIsBatchParent )
501 batchParent = currentNode;
503 currentNode = currentNode->GetParent();
509 for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
511 if( mImpl->batchParents[i].node == batchParent )
513 mImpl->batchParents[i].batchedChildren.PushBack( node );
514 node->SetBatchParent( batchParent );
515 mImpl->batchParents[i].needsUpdate = true;
522 void GeometryBatcher::RemoveNode( Node* node )
524 if( node->mBatchIndex == BATCH_NULL_HANDLE )
529 uint32_t parentIndex = BATCH_PARENT_INDEX( node->mBatchIndex );
531 BatchParent& batchParent = mImpl->batchParents[ parentIndex ];
533 // delete all batches from batch parent
534 for( size_t i = 0; i < batchParent.batches.size(); ++i )
536 Batch& batch = batchParent.batches[ i ];
539 mImpl->updateManager->RemoveGeometry( batch.geometry );
542 batchParent.batches.clear();
544 // for all children reset batch index to BATCH_NULL_HANDLE
545 for( size_t i = 0; i < batchParent.batchedChildren.Size(); )
547 Node* child = batchParent.batchedChildren[i];
551 batchParent.batchedChildren.Erase( batchParent.batchedChildren.Begin() + i );
555 child->mBatchIndex = BATCH_NULL_HANDLE;
560 mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
561 batchParent.needsUpdate = true;
564 bool GeometryBatcher::HasRendered( uint32_t batchIndex )
566 return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame == mImpl->currentFrame;
569 void GeometryBatcher::SetRendered( uint32_t batchIndex )
571 mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame = mImpl->currentFrame;
574 Render::Geometry* GeometryBatcher::GetGeometry( uint32_t batchIndex )
576 return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].geometry;
579 } // namespace SceneGraph
581 } // namespace Internal