Allow multiple renderers per Actor and sharing renderers between actors
[platform/core/uifw/dali-core.git] / dali / internal / update / node-attachments / scene-graph-image-attachment.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/node-attachments/scene-graph-image-attachment.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/common/internal-constants.h>
25
26 #include <dali/internal/update/resources/resource-manager.h>
27 #include <dali/internal/update/resources/complete-status-manager.h>
28
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>
32
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/render-image-renderer.h>
37 #include <dali/internal/render/shaders/scene-graph-shader.h>
38
39 #include <dali/internal/update/node-attachments/scene-graph-image-attachment-debug.h>
40
41 namespace Dali
42 {
43
44 namespace Internal
45 {
46
47 // value types used by messages
48 template <> struct ParameterType< Render::ImageRenderer::MeshType >
49 : public BasicType< Render::ImageRenderer::MeshType > {};
50
51 namespace SceneGraph
52 {
53
54 ImageAttachment* ImageAttachment::New( unsigned int textureId )
55 {
56   return new ImageAttachment( textureId );
57 }
58
59 ImageAttachment::ImageAttachment( unsigned int textureId )
60 : RenderableAttachment( false ), // no scaling
61   mImageRenderer( NULL ),
62   mTextureId( textureId ),
63   mRefreshMeshData( true ),
64   mIsPixelAreaSet( false ),
65   mPreviousRefreshHints( 0 ),
66   mStyle( Dali::ImageActor::STYLE_QUAD ),
67   mCullFaceMode( CullNone )
68 {
69 }
70
71 void ImageAttachment::Initialize2( BufferIndex updateBufferIndex )
72 {
73   DALI_ASSERT_DEBUG( NULL != mSceneController );
74
75   // Create main renderer, passing ownership to the render-thread
76   mImageRenderer = Render::ImageRenderer::New();
77
78   mSceneController->GetRenderMessageDispatcher().AddRenderer( *mImageRenderer );
79
80   ATTACHMENT_LOG_FMT(Debug::General, " renderer: %p\n", mImageRenderer);
81
82   if( mTextureId != 0 )
83   {
84     typedef MessageValue1< Render::ImageRenderer, ResourceId > DerivedType;
85
86     // Reserve some memory inside the render queue
87     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
88
89     // Construct message in the render queue memory; note that delete should not be called on the return value
90     new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetTextureId, mTextureId );
91   }
92
93   // After derived classes have (potentially) created their renderer
94   Render::Renderer& renderer = GetRenderer();
95   renderer.SetCullFace( mCullFaceMode );
96
97   // set the default shader here as well
98   renderer.SetShader( mShader );
99 }
100
101 void ImageAttachment::OnDestroy2()
102 {
103   DALI_ASSERT_DEBUG( NULL != mSceneController );
104
105   // Request deletion in the next Render
106   mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mImageRenderer );
107   mImageRenderer = NULL;
108 }
109
110 void ImageAttachment::ConnectedToSceneGraph()
111 {
112   // Do nothing
113 }
114
115 void ImageAttachment::DisconnectedFromSceneGraph()
116 {
117   // Do nothing
118 }
119
120 ImageAttachment::~ImageAttachment()
121 {
122 }
123
124 Render::Renderer& ImageAttachment::GetRenderer()
125 {
126   return *mImageRenderer;
127 }
128
129 const Render::Renderer& ImageAttachment::GetRenderer() const
130 {
131   return *mImageRenderer;
132 }
133
134 void ImageAttachment::SetTextureId( BufferIndex updateBufferIndex, unsigned int textureId )
135 {
136   DALI_ASSERT_DEBUG(mSceneController);
137   ATTACHMENT_LOG_FMT(Debug::General, " textureid: %d)\n", textureId);
138
139   mTextureId = textureId;
140
141   // Loading is essentially finished if we don't have a resource ID
142   mFinishedResourceAcquisition = ( 0 == mTextureId );
143
144   if( mImageRenderer )
145   {
146     typedef MessageValue1< Render::ImageRenderer, ResourceId > DerivedType;
147
148     // Reserve some memory inside the render queue
149     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
150
151     // Construct message in the render queue memory; note that delete should not be called on the return value
152     new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetTextureId, mTextureId );
153   }
154 }
155
156 void ImageAttachment::SetPixelArea( BufferIndex updateBufferIndex, const PixelArea& pixelArea )
157 {
158   // update the pixel area information
159   mIsPixelAreaSet = true;
160
161   {
162     typedef MessageValue1< Render::ImageRenderer, Render::ImageRenderer::PixelArea > DerivedType;
163
164     // Reserve some memory inside the render queue
165     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
166
167     // Construct message in the render queue memory; note that delete should not be called on the return value
168     new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetPixelArea, pixelArea );
169   }
170
171   // we rely on attachment to not call us unless it actually did change
172   mRefreshMeshData = true;
173 }
174
175 void ImageAttachment::ClearPixelArea()
176 {
177   mIsPixelAreaSet = false;
178   mRefreshMeshData = true;
179 }
180
181 void ImageAttachment::SetStyle( Dali::ImageActor::Style style )
182 {
183   if (mStyle != style)
184   {
185     mStyle = style;
186     mRefreshMeshData = true;
187   }
188 }
189
190 void ImageAttachment::SetBorder( BufferIndex updateBufferIndex, const Vector4& border, bool inPixels )
191 {
192   // update the 9 patch border information
193
194   typedef MessageValue2< Render::ImageRenderer, Vector4, bool > DerivedType;
195
196   // Reserve some memory inside the render queue
197   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
198
199   // Construct message in the render queue memory; note that delete should not be called on the return value
200   new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetNinePatchBorder, border, inPixels );
201
202   if (mStyle != Dali::ImageActor::STYLE_QUAD)
203   {
204     mRefreshMeshData = true;
205   }
206 }
207
208 void ImageAttachment::SetBlendingOptions( BufferIndex updateBufferIndex, unsigned int options )
209 {
210   // Blending options are forwarded to renderer in render-thread
211   typedef MessageValue1< Render::ImageRenderer, unsigned int > DerivedType;
212
213   // Reserve some memory inside the render queue
214   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
215
216   // Construct message in the render queue memory; note that delete should not be called on the return value
217   new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetBlendingOptions, options );
218 }
219
220 void ImageAttachment::SetBlendColor( BufferIndex updateBufferIndex, const Vector4& color )
221 {
222   // Blend color is forwarded to renderer in render-thread
223   typedef MessageValue1< Render::ImageRenderer, Vector4 > DerivedType;
224
225   // Reserve some memory inside the render queue
226   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
227
228   // Construct message in the render queue memory; note that delete should not be called on the return value
229   new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::SetBlendColor, color );
230 }
231
232 void ImageAttachment::SetCullFace( BufferIndex updateBufferIndex, CullFaceMode mode )
233 {
234   DALI_ASSERT_DEBUG(mSceneController);
235   DALI_ASSERT_DEBUG(mode >= CullNone && mode <= CullFrontAndBack);
236
237   mCullFaceMode = mode;
238
239   typedef MessageValue1< Render::Renderer, CullFaceMode > DerivedType;
240
241   // Reserve some memory inside the render queue
242   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
243
244   // Construct message in the render queue memory; note that delete should not be called on the return value
245   new (slot) DerivedType( &GetRenderer(), &Render::Renderer::SetCullFace, mode );
246 }
247
248 void ImageAttachment::SetSampler( BufferIndex updateBufferIndex, unsigned int samplerBitfield )
249 {
250   DALI_ASSERT_DEBUG(mSceneController);
251
252   typedef MessageValue1< Render::Renderer, unsigned int > DerivedType;
253
254   // Reserve some memory inside the render queue
255   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
256
257   // Construct message in the render queue memory; note that delete should not be called on the return value
258   new (slot) DerivedType( &GetRenderer(), &Render::Renderer::SetSampler, samplerBitfield );
259 }
260
261 void ImageAttachment::ApplyShader( BufferIndex updateBufferIndex, Shader* shader )
262 {
263   mShader = shader;
264
265   // send the message to renderer
266   SendShaderChangeMessage( updateBufferIndex );
267
268   // tell derived class to do something
269   ShaderChanged( updateBufferIndex );
270 }
271
272 void ImageAttachment::RemoveShader( BufferIndex updateBufferIndex )
273 {
274   // return to default shader
275   mShader = NULL;
276
277   // send the message to renderer
278   SendShaderChangeMessage( updateBufferIndex );
279
280   // tell derived class to do something
281   ShaderChanged( updateBufferIndex );
282 }
283
284
285 void ImageAttachment::ShaderChanged( BufferIndex updateBufferIndex )
286 {
287   DALI_ASSERT_DEBUG( mSceneController );
288
289   int hints = 0; // default shader hints are 0
290   if( mShader )
291   {
292     hints = mShader->GetGeometryHints();
293   }
294   if ( hints != mPreviousRefreshHints )
295   {
296     mPreviousRefreshHints = hints;
297     // (may) need to change geometry
298     mRefreshMeshData = true;
299   }
300 }
301
302 void ImageAttachment::SizeChanged( BufferIndex updateBufferIndex )
303 {
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 )
308   {
309     mRefreshMeshData = true;
310   }
311 }
312
313 bool ImageAttachment::DoPrepareResources( BufferIndex updateBufferIndex, ResourceManager& resourceManager )
314 {
315   DALI_LOG_TRACE_METHOD_FMT(gImageAttachmentLogFilter, "this:%p", this);
316   bool ready = false;
317
318   if( 0 != mTextureId )
319   {
320     // The metadata is used by IsFullyOpaque(), below.
321     mBitmapMetadata = resourceManager.GetBitmapMetadata( mTextureId );
322
323     CompleteStatusManager& completeStatusManager = mSceneController->GetCompleteStatusManager();
324     CompleteStatusManager::CompleteState status = completeStatusManager.GetStatus( mTextureId );
325
326     switch( status )
327     {
328       case CompleteStatusManager::NOT_READY:
329       {
330         ready = false;
331
332         if( mBitmapMetadata.GetIsFramebuffer() )
333         {
334           ready = true;
335         }
336         mFinishedResourceAcquisition = false;
337         FollowTracker( mTextureId );
338       }
339       break;
340
341       case CompleteStatusManager::COMPLETE:
342       {
343         ready = true;
344         mFinishedResourceAcquisition = true;
345       }
346       break;
347
348       case CompleteStatusManager::NEVER:
349       {
350         ready = false;
351         mFinishedResourceAcquisition = true;
352       }
353       break;
354     }
355   }
356   else
357   {
358     // Loading is essentially finished if we don't have a resource ID
359     mFinishedResourceAcquisition = true;
360   }
361
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");
365
366   return ready;
367 }
368
369 void ImageAttachment::DoPrepareRender( BufferIndex updateBufferIndex )
370 {
371   DALI_ASSERT_DEBUG( mSceneController && mImageRenderer );
372
373   ATTACHMENT_LOG_FMT(Debug::General, "ObjName:%s textureId:%d\n",
374                      DALI_LOG_GET_OBJECT_C_STR(mParent),
375                      mTextureId);
376
377   // Check whether we need to refresh the vertex buffer.
378   if ( mRefreshMeshData )
379   {
380     const Vector3& actorSize = GetParent().GetSize( updateBufferIndex );
381     mGeometrySize.x = actorSize.x;
382     mGeometrySize.y = actorSize.y;
383
384     Render::ImageRenderer::MeshType meshType = Render::ImageRenderer::GRID_QUAD;
385
386     if ( !PreviousHintEnabled( Dali::ShaderEffect::HINT_GRID ) )
387     {
388       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
389       {
390         meshType = Render::ImageRenderer::NINE_PATCH;
391       }
392       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
393       {
394         meshType = Render::ImageRenderer::NINE_PATCH_NO_CENTER;
395       }
396       else
397       {
398         meshType = Render::ImageRenderer::QUAD;
399       }
400     }
401     else
402     {
403       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
404       {
405         meshType = Render::ImageRenderer::GRID_NINE_PATCH;
406       }
407       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
408       {
409         meshType = Render::ImageRenderer::GRID_NINE_PATCH_NO_CENTER;
410       }
411       else
412       {
413         meshType = Render::ImageRenderer::GRID_QUAD;
414       }
415     }
416
417     // Recalculate the mesh data in the next render
418     {
419       typedef MessageValue3< Render::ImageRenderer, Render::ImageRenderer::MeshType, Vector2, bool > DerivedType;
420
421       // Reserve some memory inside the render queue
422       unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
423
424       // Construct message in the render queue memory; note that delete should not be called on the return value
425       new (slot) DerivedType( mImageRenderer, &Render::ImageRenderer::CalculateMeshData, meshType, mGeometrySize, mIsPixelAreaSet );
426     }
427
428     mRefreshMeshData = false;
429   }
430 }
431
432 void RenderableAttachment::SetBlendingMode( BlendingMode::Type mode )
433 {
434   mBlendingMode = mode;
435 }
436
437 BlendingMode::Type RenderableAttachment::GetBlendingMode() const
438 {
439   return mBlendingMode;
440 }
441
442 bool ImageAttachment::IsFullyOpaque( BufferIndex updateBufferIndex )
443 {
444   bool fullyOpaque = true;
445
446   switch( mBlendingMode )
447   {
448     case BlendingMode::OFF:
449     {
450       fullyOpaque = true;
451       break;
452     }
453     case BlendingMode::ON:
454     {
455       // Blending always.
456       fullyOpaque = false;
457       break;
458     }
459     case BlendingMode::AUTO:
460     {
461       /**
462        * Fully opaque when...
463        *   1) not using the alpha channel from the image data
464        *   2) the inherited color is not transparent nor semi-transparent
465        *   3) the shader doesn't require blending
466        */
467       fullyOpaque = mBitmapMetadata.IsFullyOpaque();
468
469       if ( fullyOpaque && mParent )
470       {
471         fullyOpaque = ( mParent->GetWorldColor(updateBufferIndex).a >= FULLY_OPAQUE );
472
473         if ( fullyOpaque && mShader != NULL )
474         {
475           fullyOpaque = !PreviousHintEnabled( Dali::ShaderEffect::HINT_BLENDING );
476         }
477       }
478     }
479   }
480   return fullyOpaque;
481 }
482
483 void ImageAttachment::SendShaderChangeMessage( BufferIndex updateBufferIndex )
484 {
485   typedef MessageValue1< Render::Renderer, Shader* > DerivedType;
486   // Reserve memory inside the render queue
487   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
488   // Construct message in the mRenderer queue memory; note that delete should not be called on the return value
489   new (slot) DerivedType( &GetRenderer(), &Render::Renderer::SetShader, mShader );
490 }
491
492
493
494 } // namespace SceneGraph
495
496 } // namespace Internal
497
498 } // namespace Dali