[dali_1.1.7] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / images / buffer-image-impl.cpp
1 /*
2  * Copyright (c) 2015 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/event/images/buffer-image-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <string.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/internal/event/common/thread-local-storage.h>
27 #include <dali/internal/event/resources/resource-client.h>
28 #include <dali/internal/update/manager/update-manager.h>
29 #include <dali/internal/event/images/image-factory.h>
30
31 using namespace Dali::Integration;
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37
38 namespace
39 {
40 TypeRegistration mType( typeid( Dali::BufferImage ), typeid( Dali::Image ), NULL );
41 } // unnamed namespace
42
43 BufferImagePtr BufferImage::New( unsigned int width,
44                                  unsigned int height,
45                                  Pixel::Format pixelformat,
46                                  ReleasePolicy releasePol )
47 {
48   BufferImagePtr internal = new BufferImage( width, height, pixelformat, releasePol );
49   internal->Initialize();
50   return internal;
51 }
52
53 BufferImagePtr BufferImage::New( PixelBuffer* pixBuf,
54                                  unsigned int width,
55                                  unsigned int height,
56                                  Pixel::Format pixelformat,
57                                  unsigned int stride,
58                                  ReleasePolicy releasePol )
59 {
60   BufferImagePtr internal = new BufferImage( pixBuf, width, height, pixelformat, stride, releasePol );
61   internal->Initialize();
62   return internal;
63 }
64
65 BufferImage::BufferImage(unsigned int width, unsigned int height, Pixel::Format pixelformat, ReleasePolicy releasePol)
66 : Image(releasePol),
67   mInternalBuffer(NULL),
68   mExternalBuffer(NULL)
69 {
70   SetupBuffer( width, height, pixelformat, width, releasePol );
71
72   // Allocate a persistent internal buffer
73   mInternalBuffer = new PixelBuffer[ mBufferSize ];
74 }
75
76 BufferImage::BufferImage(PixelBuffer* pixBuf,
77                          unsigned int width,
78                          unsigned int height,
79                          Pixel::Format pixelformat,
80                          unsigned int stride,
81                          ReleasePolicy releasePol )
82 : Image(releasePol),
83   mInternalBuffer(NULL),
84   mExternalBuffer(pixBuf)
85 {
86   SetupBuffer( width, height, pixelformat, stride ? stride: width, releasePol );
87 }
88
89 BufferImage::~BufferImage()
90 {
91   delete[] mInternalBuffer;
92 }
93
94 void BufferImage::SetupBuffer( unsigned int width,
95                                unsigned int height,
96                                Pixel::Format pixelformat,
97                                unsigned int byteStride,
98                                ReleasePolicy releasePol )
99 {
100   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
101   mResourceClient = &tls.GetResourceClient();
102   mWidth  = width;
103   mHeight = height;
104   mPixelFormat = pixelformat;
105   mBytesPerPixel = Pixel::GetBytesPerPixel( pixelformat );
106
107   mByteStride = byteStride * mBytesPerPixel;
108   mBufferSize = height * mByteStride;
109
110   // Respect the desired release policy
111   mResourcePolicy = releasePol == Dali::Image::UNUSED ? ResourcePolicy::OWNED_DISCARD : ResourcePolicy::OWNED_RETAIN;
112 }
113
114 bool BufferImage::IsDataExternal() const
115 {
116   return ( mExternalBuffer ? true : false );
117 }
118
119 void BufferImage::Update( RectArea& updateArea )
120 {
121   if ( !mTicket )
122   {
123     CreateHostBitmap();
124   }
125   DALI_ASSERT_DEBUG( updateArea.x + updateArea.width <= mWidth && updateArea.y + updateArea.height <= mHeight );
126   UploadArea( mTicket->GetId(), updateArea );
127 }
128
129 void BufferImage::CreateHostBitmap()
130 {
131   Integration::Bitmap* bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, mResourcePolicy );
132   Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
133   DALI_ASSERT_DEBUG(packedBitmap);
134
135   packedBitmap->ReserveBuffer( mPixelFormat, mWidth, mHeight );
136   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
137   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= mHeight * mWidth * mBytesPerPixel );
138
139   mTicket = mResourceClient->AddBitmapImage( bitmap );
140   mTicket->AddObserver(*this);
141 }
142
143 void BufferImage::UploadArea( ResourceId destId, const RectArea& area )
144 {
145   Integration::Bitmap* bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, mResourcePolicy );
146   Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
147   DALI_ASSERT_DEBUG(packedBitmap);
148   DALI_ASSERT_DEBUG( area.width <= mWidth && area.height <= mHeight );
149
150   mBufferWidth = area.width ? area.width : mWidth;
151   packedBitmap->ReserveBuffer( mPixelFormat, mBufferWidth, area.height ? area.height : mHeight );
152   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
153   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= mBufferWidth * ( area.height ? area.height : mHeight ) * mBytesPerPixel );
154
155   // Are we uploading from an external or internal buffer ?
156   if ( mExternalBuffer )
157   {
158     // Check if we're doing the entire area without stride mismatch between source and dest ?
159     if( ( mByteStride == mWidth * mBytesPerPixel ) && area.IsEmpty() )
160     {
161       memcpy( bitmap->GetBuffer(), mExternalBuffer, mBufferSize );
162     }
163     else
164     {
165       UpdateBufferArea( mExternalBuffer, bitmap->GetBuffer(), area );
166     }
167   }
168   else
169   {
170     // Check if we're doing the entire internal buffer ?
171     if( area.IsEmpty() )
172     {
173       memcpy( bitmap->GetBuffer(), mInternalBuffer, bitmap->GetBufferSize() );
174     }
175     else
176     {
177       UpdateBufferArea( mInternalBuffer, bitmap->GetBuffer(), area );
178     }
179   }
180   mResourceClient->UploadBitmap( destId, bitmap, area.x, area.y );
181
182 }
183
184 void BufferImage::UploadBitmap( ResourceId destId, std::size_t xOffset, std::size_t yOffset )
185 {
186   RectArea area( xOffset, yOffset, 0, 0 );
187   if ( !mTicket )
188   {
189     CreateHostBitmap();
190   }
191
192   UploadArea( destId, area );
193 }
194
195 void BufferImage::UpdateBufferArea( PixelBuffer* src, PixelBuffer* dest, const RectArea& area )
196 {
197   DALI_ASSERT_DEBUG( area.x + area.width <= mWidth && area.y + area.height <= mHeight );
198
199   uint32_t width = mBufferWidth * mBytesPerPixel;
200
201   src += ( area.y * mByteStride ) + ( area.x * mBytesPerPixel );
202   for ( uint32_t i = 0; i < area.height; ++i )
203   {
204     memcpy( dest, src, width );
205     src += mByteStride;
206     dest += width;
207   }
208 }
209
210 void BufferImage::Connect()
211 {
212   if ( !mConnectionCount++ )
213   {
214     RectArea area;
215     Update( area );
216   }
217 }
218
219 void BufferImage::Disconnect()
220 {
221   if ( mTicket )
222   {
223     if ( !( --mConnectionCount ) && mReleasePolicy == Dali::Image::UNUSED )
224     {
225       mTicket->RemoveObserver(*this);
226       mTicket.Reset();
227     }
228   }
229 }
230
231 } // namespace Internal
232
233 } // namespace Dali