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/update/node-attachments/scene-graph-image-attachment.h>
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/common/internal-constants.h>
26 #include <dali/internal/update/resources/resource-manager.h>
27 #include <dali/internal/update/resources/complete-status-manager.h>
29 #include <dali/internal/update/controllers/render-message-dispatcher.h>
30 #include <dali/internal/update/controllers/scene-controller.h>
31 #include <dali/internal/update/nodes/node.h>
33 #include <dali/internal/render/queue/render-queue.h>
34 #include <dali/internal/render/common/vertex.h>
35 #include <dali/internal/render/common/performance-monitor.h>
36 #include <dali/internal/render/renderers/scene-graph-image-renderer.h>
37 #include <dali/internal/render/renderers/scene-graph-renderer-declarations.h>
38 #include <dali/internal/render/shaders/scene-graph-shader.h>
40 #include <dali/internal/update/node-attachments/scene-graph-image-attachment-debug.h>
48 // value types used by messages
49 template <> struct ParameterType< SceneGraph::ImageRenderer::MeshType >
50 : public BasicType< SceneGraph::ImageRenderer::MeshType > {};
55 ImageAttachment* ImageAttachment::New( unsigned int textureId )
57 return new ImageAttachment( textureId );
60 ImageAttachment::ImageAttachment( unsigned int textureId )
61 : RenderableAttachment( false ), // no scaling
62 mImageRenderer( NULL ),
63 mTextureId( textureId ),
64 mRefreshMeshData( true ),
65 mIsPixelAreaSet( false ),
66 mPreviousRefreshHints( 0 ),
67 mStyle( Dali::ImageActor::STYLE_QUAD ),
68 mCullFaceMode( CullNone ),
73 void ImageAttachment::Initialize2( BufferIndex updateBufferIndex )
75 DALI_ASSERT_DEBUG( NULL != mSceneController );
77 // Get a reusable renderer from the pool
78 mImageRenderer = mSceneController->NewImageRenderer( *mParent );
80 mSceneController->GetRenderMessageDispatcher().AddImageRenderer( mImageRenderer, mParent );
82 ATTACHMENT_LOG_FMT(Debug::General, " renderer: %p\n", mImageRenderer);
86 typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
88 // Reserve some memory inside the render queue
89 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
91 // Construct message in the render queue memory; note that delete should not be called on the return value
92 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetTextureId, mTextureId );
95 // send messages to renderer
96 SendCullFaceChangeMessage( updateBufferIndex );
97 SendShaderChangeMessage( updateBufferIndex );
100 void ImageAttachment::OnDestroy2()
102 DALI_ASSERT_DEBUG( NULL != mSceneController );
104 if( NULL != mImageRenderer )
106 // Request GL cleanup in the next Render
107 mSceneController->GetRenderMessageDispatcher().RemoveImageRenderer( mImageRenderer );
109 // Return reusable renderer to the pool
110 mSceneController->FreeImageRenderer( *mImageRenderer );
112 mImageRenderer = NULL;
116 void ImageAttachment::ConnectedToSceneGraph()
121 void ImageAttachment::DisconnectedFromSceneGraph()
126 ImageAttachment::~ImageAttachment()
130 Renderer& ImageAttachment::GetRenderer()
132 return *mImageRenderer;
135 const Renderer& ImageAttachment::GetRenderer() const
137 return *mImageRenderer;
140 void ImageAttachment::SetTextureId( BufferIndex updateBufferIndex, unsigned int textureId )
142 DALI_ASSERT_DEBUG(mSceneController);
143 ATTACHMENT_LOG_FMT(Debug::General, " textureid: %d)\n", textureId);
145 mTextureId = textureId;
147 // Loading is essentially finished if we don't have a resource ID
148 mFinishedResourceAcquisition = ( 0 == mTextureId );
152 typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
154 // Reserve some memory inside the render queue
155 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
157 // Construct message in the render queue memory; note that delete should not be called on the return value
158 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetTextureId, mTextureId );
162 void ImageAttachment::SetPixelArea( BufferIndex updateBufferIndex, const PixelArea& pixelArea )
164 // update the pixel area information
165 mIsPixelAreaSet = true;
168 typedef MessageValue1< ImageRenderer, ImageRenderer::PixelArea > DerivedType;
170 // Reserve some memory inside the render queue
171 unsigned int* slot = mSceneController->GetRenderQueue().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( mImageRenderer, &ImageRenderer::SetPixelArea, pixelArea );
177 // we rely on attachment to not call us unless it actually did change
178 mRefreshMeshData = true;
181 void ImageAttachment::ClearPixelArea()
183 mIsPixelAreaSet = false;
184 mRefreshMeshData = true;
187 void ImageAttachment::SetStyle( Dali::ImageActor::Style style )
192 mRefreshMeshData = true;
196 void ImageAttachment::SetBorder( BufferIndex updateBufferIndex, const Vector4& border, bool inPixels )
198 // update the 9 patch border information
200 typedef MessageValue2< ImageRenderer, Vector4, bool > DerivedType;
202 // Reserve some memory inside the render queue
203 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
205 // Construct message in the render queue memory; note that delete should not be called on the return value
206 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetNinePatchBorder, border, inPixels );
208 if (mStyle != Dali::ImageActor::STYLE_QUAD)
210 mRefreshMeshData = true;
214 void ImageAttachment::SetBlendingOptions( BufferIndex updateBufferIndex, unsigned int options )
216 // Blending options are forwarded to renderer in render-thread
217 typedef MessageValue1< ImageRenderer, unsigned int > DerivedType;
219 // Reserve some memory inside the render queue
220 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
222 // Construct message in the render queue memory; note that delete should not be called on the return value
223 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetBlendingOptions, options );
226 void ImageAttachment::SetBlendColor( BufferIndex updateBufferIndex, const Vector4& color )
228 // Blend color is forwarded to renderer in render-thread
229 typedef MessageValue1< ImageRenderer, Vector4 > DerivedType;
231 // Reserve some memory inside the render queue
232 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
234 // Construct message in the render queue memory; note that delete should not be called on the return value
235 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetBlendColor, color );
238 void ImageAttachment::SetCullFace( BufferIndex updateBufferIndex, CullFaceMode mode )
240 DALI_ASSERT_DEBUG(mSceneController);
241 DALI_ASSERT_DEBUG(mode >= CullNone && mode <= CullFrontAndBack);
243 mCullFaceMode = mode;
245 SendCullFaceChangeMessage( updateBufferIndex );
248 void ImageAttachment::SetSampler( BufferIndex updateBufferIndex, unsigned int samplerBitfield )
250 DALI_ASSERT_DEBUG(mSceneController);
252 typedef MessageValue1< Renderer, unsigned int > DerivedType;
254 // Reserve some memory inside the render queue
255 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
257 // Construct message in the render queue memory; note that delete should not be called on the return value
258 new (slot) DerivedType( &GetRenderer(), &Renderer::SetSampler, samplerBitfield );
261 void ImageAttachment::ApplyShader( BufferIndex updateBufferIndex, Shader* shader )
265 // send the message to renderer
266 SendShaderChangeMessage( updateBufferIndex );
268 // tell derived class to do something
269 ShaderChanged( updateBufferIndex );
272 void ImageAttachment::RemoveShader( BufferIndex updateBufferIndex )
274 // return to default shader
277 // send the message to renderer
278 SendShaderChangeMessage( updateBufferIndex );
280 // tell derived class to do something
281 ShaderChanged( updateBufferIndex );
285 void ImageAttachment::ShaderChanged( BufferIndex updateBufferIndex )
287 DALI_ASSERT_DEBUG( mSceneController );
289 int hints = 0; // default shader hints are 0
292 hints = mShader->GetGeometryHints();
294 if ( hints != mPreviousRefreshHints )
296 mPreviousRefreshHints = hints;
297 // (may) need to change geometry
298 mRefreshMeshData = true;
302 void ImageAttachment::SizeChanged( BufferIndex updateBufferIndex )
304 // avoid regenerating geometry if the size did not actually change (visibility change can accumulate a false SizeChanged)
305 const Vector3& actorSize = GetParent().GetSize( updateBufferIndex );
306 if( fabsf( actorSize.width - mGeometrySize.width ) > Math::MACHINE_EPSILON_1 ||
307 fabsf( actorSize.height - mGeometrySize.height ) > Math::MACHINE_EPSILON_1 )
309 mRefreshMeshData = true;
313 bool ImageAttachment::DoPrepareResources( BufferIndex updateBufferIndex, ResourceManager& resourceManager )
315 DALI_LOG_TRACE_METHOD_FMT(gImageAttachmentLogFilter, "this:%p", this);
318 if( 0 != mTextureId )
320 // The metadata is used by IsFullyOpaque(), below.
321 mBitmapMetadata = resourceManager.GetBitmapMetadata( mTextureId );
323 CompleteStatusManager& completeStatusManager = mSceneController->GetCompleteStatusManager();
324 CompleteStatusManager::CompleteState status = completeStatusManager.GetStatus( mTextureId );
328 case CompleteStatusManager::NOT_READY:
332 if( mBitmapMetadata.GetIsFramebuffer() )
336 mFinishedResourceAcquisition = false;
337 FollowTracker( mTextureId );
341 case CompleteStatusManager::COMPLETE:
344 mFinishedResourceAcquisition = true;
348 case CompleteStatusManager::NEVER:
351 mFinishedResourceAcquisition = true;
358 // Loading is essentially finished if we don't have a resource ID
359 mFinishedResourceAcquisition = true;
362 ATTACHMENT_LOG_FMT(Debug::General, " ObjName:%s finished:%s ready:%s \n",
363 DALI_LOG_GET_OBJECT_C_STR(mParent),
364 mFinishedResourceAcquisition?"T":"F", ready?"T":"F");
369 void ImageAttachment::DoPrepareRender( BufferIndex updateBufferIndex )
371 DALI_ASSERT_DEBUG( mSceneController && mImageRenderer );
373 ATTACHMENT_LOG_FMT(Debug::General, "ObjName:%s textureId:%d\n",
374 DALI_LOG_GET_OBJECT_C_STR(mParent),
377 // Check whether we need to refresh the vertex buffer.
378 if ( mRefreshMeshData )
380 const Vector3& actorSize = GetParent().GetSize( updateBufferIndex );
381 mGeometrySize.x = actorSize.x;
382 mGeometrySize.y = actorSize.y;
384 ImageRenderer::MeshType meshType = ImageRenderer::GRID_QUAD;
386 if ( !PreviousHintEnabled( Dali::ShaderEffect::HINT_GRID ) )
388 if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
390 meshType = ImageRenderer::NINE_PATCH;
392 else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
394 meshType = ImageRenderer::NINE_PATCH_NO_CENTER;
398 meshType = ImageRenderer::QUAD;
403 if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
405 meshType = ImageRenderer::GRID_NINE_PATCH;
407 else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
409 meshType = ImageRenderer::GRID_NINE_PATCH_NO_CENTER;
413 meshType = ImageRenderer::GRID_QUAD;
417 // Recalculate the mesh data in the next render
419 typedef MessageValue3< ImageRenderer, ImageRenderer::MeshType, Vector2, bool > DerivedType;
421 // Reserve some memory inside the render queue
422 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
424 // Construct message in the render queue memory; note that delete should not be called on the return value
425 new (slot) DerivedType( mImageRenderer, &ImageRenderer::CalculateMeshData, meshType, mGeometrySize, mIsPixelAreaSet );
428 mRefreshMeshData = false;
431 bool blend = !IsFullyOpaque( updateBufferIndex );
433 if ( mUseBlend != blend )
437 // Enable/disable blending in the next render
438 typedef MessageValue1< ImageRenderer, bool > DerivedType;
440 // Reserve some memory inside the render queue
441 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
443 // Construct message in the render queue memory; note that delete should not be called on the return value
444 new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetUseBlend, blend );
448 void RenderableAttachment::SetBlendingMode( BlendingMode::Type mode )
450 mBlendingMode = mode;
453 BlendingMode::Type RenderableAttachment::GetBlendingMode() const
455 return mBlendingMode;
458 bool ImageAttachment::IsFullyOpaque( BufferIndex updateBufferIndex )
460 bool fullyOpaque = true;
462 switch( mBlendingMode )
464 case BlendingMode::OFF:
469 case BlendingMode::ON:
475 case BlendingMode::AUTO:
478 * Fully opaque when...
479 * 1) not using the alpha channel from the image data
480 * 2) the inherited color is not transparent nor semi-transparent
481 * 3) the shader doesn't require blending
483 fullyOpaque = mBitmapMetadata.IsFullyOpaque();
485 if ( fullyOpaque && mParent )
487 fullyOpaque = ( mParent->GetWorldColor(updateBufferIndex).a >= FULLY_OPAQUE );
489 if ( fullyOpaque && mShader != NULL )
491 fullyOpaque = !PreviousHintEnabled( Dali::ShaderEffect::HINT_BLENDING );
499 void ImageAttachment::SendCullFaceChangeMessage( BufferIndex updateBufferIndex )
501 typedef MessageValue1< Renderer, CullFaceMode > DerivedType;
503 // Reserve some memory inside the render queue
504 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
506 // Construct message in the render queue memory; note that delete should not be called on the return value
507 new (slot) DerivedType( &GetRenderer(), &Renderer::SetCullFace, mCullFaceMode );
510 void ImageAttachment::SendShaderChangeMessage( BufferIndex updateBufferIndex )
512 typedef MessageValue1< Renderer, Shader* > DerivedType;
513 // Reserve memory inside the render queue
514 unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
515 // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
516 new (slot) DerivedType( &GetRenderer(), &Renderer::SetShader, mShader );
521 } // namespace SceneGraph
523 } // namespace Internal