Tizen 2.4.0 rev3 SDK Public Release
[framework/graphics/dali.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/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>
39
40 #include <dali/internal/update/node-attachments/scene-graph-image-attachment-debug.h>
41
42 namespace Dali
43 {
44
45 namespace Internal
46 {
47
48 // value types used by messages
49 template <> struct ParameterType< SceneGraph::ImageRenderer::MeshType >
50 : public BasicType< SceneGraph::ImageRenderer::MeshType > {};
51
52 namespace SceneGraph
53 {
54
55 ImageAttachment* ImageAttachment::New( unsigned int textureId )
56 {
57   return new ImageAttachment( textureId );
58 }
59
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 ),
69   mUseBlend( false )
70 {
71 }
72
73 void ImageAttachment::Initialize2( BufferIndex updateBufferIndex )
74 {
75   DALI_ASSERT_DEBUG( NULL != mSceneController );
76
77   // Get a reusable renderer from the pool
78   mImageRenderer = mSceneController->NewImageRenderer( *mParent );
79
80   mSceneController->GetRenderMessageDispatcher().AddImageRenderer( mImageRenderer, mParent );
81
82   ATTACHMENT_LOG_FMT(Debug::General, " renderer: %p\n", mImageRenderer);
83
84   if( mTextureId != 0 )
85   {
86     typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
87
88     // Reserve some memory inside the render queue
89     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
90
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 );
93   }
94
95   // send messages to renderer
96   SendCullFaceChangeMessage( updateBufferIndex );
97   SendShaderChangeMessage( updateBufferIndex );
98 }
99
100 void ImageAttachment::OnDestroy2()
101 {
102   DALI_ASSERT_DEBUG( NULL != mSceneController );
103
104   if( NULL != mImageRenderer )
105   {
106     // Request GL cleanup in the next Render
107     mSceneController->GetRenderMessageDispatcher().RemoveImageRenderer( mImageRenderer );
108
109     // Return reusable renderer to the pool
110     mSceneController->FreeImageRenderer( *mImageRenderer );
111
112     mImageRenderer = NULL;
113   }
114 }
115
116 void ImageAttachment::ConnectedToSceneGraph()
117 {
118   // Do nothing
119 }
120
121 void ImageAttachment::DisconnectedFromSceneGraph()
122 {
123   // Do nothing
124 }
125
126 ImageAttachment::~ImageAttachment()
127 {
128 }
129
130 Renderer& ImageAttachment::GetRenderer()
131 {
132   return *mImageRenderer;
133 }
134
135 const Renderer& ImageAttachment::GetRenderer() const
136 {
137   return *mImageRenderer;
138 }
139
140 void ImageAttachment::SetTextureId( BufferIndex updateBufferIndex, unsigned int textureId )
141 {
142   DALI_ASSERT_DEBUG(mSceneController);
143   ATTACHMENT_LOG_FMT(Debug::General, " textureid: %d)\n", textureId);
144
145   mTextureId = textureId;
146
147   // Loading is essentially finished if we don't have a resource ID
148   mFinishedResourceAcquisition = ( 0 == mTextureId );
149
150   if( mImageRenderer )
151   {
152     typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
153
154     // Reserve some memory inside the render queue
155     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
156
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 );
159   }
160 }
161
162 void ImageAttachment::SetPixelArea( BufferIndex updateBufferIndex, const PixelArea& pixelArea )
163 {
164   // update the pixel area information
165   mIsPixelAreaSet = true;
166
167   {
168     typedef MessageValue1< ImageRenderer, ImageRenderer::PixelArea > DerivedType;
169
170     // Reserve some memory inside the render queue
171     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
172
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 );
175   }
176
177   // we rely on attachment to not call us unless it actually did change
178   mRefreshMeshData = true;
179 }
180
181 void ImageAttachment::ClearPixelArea()
182 {
183   mIsPixelAreaSet = false;
184   mRefreshMeshData = true;
185 }
186
187 void ImageAttachment::SetStyle( Dali::ImageActor::Style style )
188 {
189   if (mStyle != style)
190   {
191     mStyle = style;
192     mRefreshMeshData = true;
193   }
194 }
195
196 void ImageAttachment::SetBorder( BufferIndex updateBufferIndex, const Vector4& border, bool inPixels )
197 {
198   // update the 9 patch border information
199
200   typedef MessageValue2< ImageRenderer, Vector4, bool > DerivedType;
201
202   // Reserve some memory inside the render queue
203   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
204
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 );
207
208   if (mStyle != Dali::ImageActor::STYLE_QUAD)
209   {
210     mRefreshMeshData = true;
211   }
212 }
213
214 void ImageAttachment::SetBlendingOptions( BufferIndex updateBufferIndex, unsigned int options )
215 {
216   // Blending options are forwarded to renderer in render-thread
217   typedef MessageValue1< ImageRenderer, unsigned int > DerivedType;
218
219   // Reserve some memory inside the render queue
220   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
221
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 );
224 }
225
226 void ImageAttachment::SetBlendColor( BufferIndex updateBufferIndex, const Vector4& color )
227 {
228   // Blend color is forwarded to renderer in render-thread
229   typedef MessageValue1< ImageRenderer, Vector4 > DerivedType;
230
231   // Reserve some memory inside the render queue
232   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
233
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 );
236 }
237
238 void ImageAttachment::SetCullFace( BufferIndex updateBufferIndex, CullFaceMode mode )
239 {
240   DALI_ASSERT_DEBUG(mSceneController);
241   DALI_ASSERT_DEBUG(mode >= CullNone && mode <= CullFrontAndBack);
242
243   mCullFaceMode = mode;
244
245   SendCullFaceChangeMessage( updateBufferIndex );
246 }
247
248 void ImageAttachment::SetSampler( BufferIndex updateBufferIndex, unsigned int samplerBitfield )
249 {
250   DALI_ASSERT_DEBUG(mSceneController);
251
252   typedef MessageValue1< 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(), &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     ImageRenderer::MeshType meshType = ImageRenderer::GRID_QUAD;
385
386     if ( !PreviousHintEnabled( Dali::ShaderEffect::HINT_GRID ) )
387     {
388       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
389       {
390         meshType = ImageRenderer::NINE_PATCH;
391       }
392       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
393       {
394         meshType = ImageRenderer::NINE_PATCH_NO_CENTER;
395       }
396       else
397       {
398         meshType = ImageRenderer::QUAD;
399       }
400     }
401     else
402     {
403       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
404       {
405         meshType = ImageRenderer::GRID_NINE_PATCH;
406       }
407       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
408       {
409         meshType = ImageRenderer::GRID_NINE_PATCH_NO_CENTER;
410       }
411       else
412       {
413         meshType = ImageRenderer::GRID_QUAD;
414       }
415     }
416
417     // Recalculate the mesh data in the next render
418     {
419       typedef MessageValue3< ImageRenderer, 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, &ImageRenderer::CalculateMeshData, meshType, mGeometrySize, mIsPixelAreaSet );
426     }
427
428     mRefreshMeshData = false;
429   }
430
431   bool blend = !IsFullyOpaque( updateBufferIndex );
432
433   if ( mUseBlend != blend )
434   {
435     mUseBlend = blend;
436
437     // Enable/disable blending in the next render
438     typedef MessageValue1< ImageRenderer, bool > DerivedType;
439
440     // Reserve some memory inside the render queue
441     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
442
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 );
445   }
446 }
447
448 void RenderableAttachment::SetBlendingMode( BlendingMode::Type mode )
449 {
450   mBlendingMode = mode;
451 }
452
453 BlendingMode::Type RenderableAttachment::GetBlendingMode() const
454 {
455   return mBlendingMode;
456 }
457
458 bool ImageAttachment::IsFullyOpaque( BufferIndex updateBufferIndex )
459 {
460   bool fullyOpaque = true;
461
462   switch( mBlendingMode )
463   {
464     case BlendingMode::OFF:
465     {
466       fullyOpaque = true;
467       break;
468     }
469     case BlendingMode::ON:
470     {
471       // Blending always.
472       fullyOpaque = false;
473       break;
474     }
475     case BlendingMode::AUTO:
476     {
477       /**
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
482        */
483       fullyOpaque = mBitmapMetadata.IsFullyOpaque();
484
485       if ( fullyOpaque && mParent )
486       {
487         fullyOpaque = ( mParent->GetWorldColor(updateBufferIndex).a >= FULLY_OPAQUE );
488
489         if ( fullyOpaque && mShader != NULL )
490         {
491           fullyOpaque = !PreviousHintEnabled( Dali::ShaderEffect::HINT_BLENDING );
492         }
493       }
494     }
495   }
496   return fullyOpaque;
497 }
498
499 void ImageAttachment::SendCullFaceChangeMessage( BufferIndex updateBufferIndex )
500 {
501   typedef MessageValue1< Renderer, CullFaceMode > DerivedType;
502
503   // Reserve some memory inside the render queue
504   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
505
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 );
508 }
509
510 void ImageAttachment::SendShaderChangeMessage( BufferIndex updateBufferIndex )
511 {
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 );
517 }
518
519
520
521 } // namespace SceneGraph
522
523 } // namespace Internal
524
525 } // namespace Dali