Merge "BufferImage mirrors an external Pixel Buffer on creation." into 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, unsigned int height, Pixel::Format pixelformat, ReleasePolicy releasePol )
44 {
45   BufferImagePtr internal = new BufferImage( width, height, pixelformat, releasePol );
46   internal->Initialize();
47   return internal;
48 }
49
50 BufferImagePtr BufferImage::New( PixelBuffer* pixBuf, unsigned int width, unsigned int height, Pixel::Format pixelformat, unsigned int stride, ReleasePolicy releasePol )
51 {
52   BufferImagePtr internal = new BufferImage( pixBuf, width, height, pixelformat, stride, releasePol );
53   internal->Initialize();
54   return internal;
55 }
56
57 BufferImage::BufferImage(unsigned int width, unsigned int height, Pixel::Format pixelformat, ReleasePolicy releasePol)
58 : Image(releasePol),
59   mInternalBuffer(NULL),
60   mExternalBuffer(NULL),
61   mBitmap(NULL)
62 {
63   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
64   mResourceClient = &tls.GetResourceClient();
65   mWidth  = width;
66   mHeight = height;
67   mPixelFormat = pixelformat;
68   mBytesPerPixel = Pixel::GetBytesPerPixel( pixelformat );
69   mByteStride = width * mBytesPerPixel;
70   mBufferSize = height * mByteStride;
71
72   // Allocate a persistent internal buffer
73   mInternalBuffer = new PixelBuffer[ mBufferSize ];
74
75   // Respect the desired release policy
76   mResourcePolicy = releasePol == Dali::Image::UNUSED ? ResourcePolicy::OWNED_DISCARD : ResourcePolicy::OWNED_RETAIN;
77 }
78
79 BufferImage::BufferImage(PixelBuffer* pixBuf, unsigned int width, unsigned int height, Pixel::Format pixelformat, unsigned int stride, ReleasePolicy releasePol )
80 : Image(releasePol),
81   mInternalBuffer(NULL),
82   mExternalBuffer(pixBuf),
83   mBitmap(NULL)
84 {
85   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
86   mResourceClient = &tls.GetResourceClient();
87   mWidth  = width;
88   mHeight = height;
89   mPixelFormat = pixelformat;
90   mBytesPerPixel = Pixel::GetBytesPerPixel( pixelformat );
91   mByteStride = ( stride ? stride : mWidth ) * mBytesPerPixel;
92   mBufferSize = height * mByteStride;
93
94   // Respect the desired release policy
95   mResourcePolicy = releasePol == Dali::Image::UNUSED ? ResourcePolicy::OWNED_DISCARD : ResourcePolicy::OWNED_RETAIN;
96
97   // Create a bitmap to hold copy of external buffer
98   ReserveBitmap();
99
100   // Take a copy of the external buffer immediately, so it can be released if desired
101   RectArea area;
102   MirrorExternal( area );
103 }
104
105 BufferImage::~BufferImage()
106 {
107   delete[] mInternalBuffer;
108 }
109
110 bool BufferImage::IsDataExternal() const
111 {
112   return ( mExternalBuffer ? true : false );
113 }
114
115 void BufferImage::Update( RectArea& updateArea )
116 {
117   ValidateBitmap();
118   UpdateBitmap( updateArea );
119
120   if (mTicket)
121   {
122     DALI_ASSERT_DEBUG( updateArea.x + updateArea.width <= mWidth && updateArea.y + updateArea.height <= mHeight );
123     mResourceClient->UpdateBitmapArea( mTicket, updateArea );
124
125     // Bitmap ownership has been passed on, so any subsequent update will need another bitmap
126     mBitmap = NULL;
127   }
128 }
129
130 void BufferImage::UpdateBitmap( RectArea& updateArea )
131 {
132   if ( mExternalBuffer )
133   {
134     MirrorExternal( updateArea );
135   }
136   else
137   {
138     // Copy the internal buffer to the bitmap area
139     memcpy( mBitmap->GetBuffer(), mInternalBuffer, mBufferSize );
140   }
141 }
142
143 void BufferImage::ValidateBitmap()
144 {
145   ReserveBitmap();
146   if ( !mTicket )
147   {
148     mTicket = mResourceClient->AddBitmapImage( mBitmap );
149     mTicket->AddObserver(*this);
150   }
151 }
152
153 void BufferImage::ReserveBitmap()
154 {
155    // Does a bitmap currently exist ?
156   if ( !mBitmap )
157   {
158     mBitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, mResourcePolicy );
159   }
160
161   if ( !mBitmap->GetBuffer() )
162   {
163     Bitmap::PackedPixelsProfile* const packedBitmap = mBitmap->GetPackedPixelsProfile();
164     DALI_ASSERT_DEBUG(packedBitmap);
165
166     packedBitmap->ReserveBuffer( mPixelFormat, mWidth, mHeight, mByteStride / mBytesPerPixel, mHeight );
167     DALI_ASSERT_DEBUG(mBitmap->GetBuffer() != 0);
168     DALI_ASSERT_DEBUG(mBitmap->GetBufferSize() >= mWidth * mHeight * Pixel::GetBytesPerPixel( mBitmap->GetPixelFormat() ) );
169   }
170 }
171
172 void BufferImage::UploadBitmap( ResourceId destId, std::size_t xOffset, std::size_t yOffset )
173 {
174   // Make sure we have a bitmap for transport
175   ReserveBitmap();
176
177   // Copy source pixel data into bitmap
178   RectArea area;
179   UpdateBitmap( area );
180
181   mResourceClient->UploadBitmap( destId, mBitmap, xOffset, yOffset);
182   mBitmap = NULL;
183 }
184
185 void BufferImage::UpdateBufferArea( PixelBuffer* src, const RectArea& area )
186 {
187   DALI_ASSERT_DEBUG( area.x + area.width <= mWidth && area.y + area.height <= mHeight );
188
189   PixelBuffer* dest = mBitmap->GetBuffer();
190   uint32_t width = area.width * mBytesPerPixel;
191   uint32_t stride = mWidth * mBytesPerPixel;
192
193   src += ( area.y * mByteStride ) + ( area.x * mBytesPerPixel );
194   dest +=( ( area.y * mWidth ) + area.x ) * mBytesPerPixel;
195   for ( uint32_t i = 0; i < area.height; ++i )
196   {
197     memcpy( dest, src, width );
198     src += mByteStride;
199     dest += stride;
200   }
201 }
202
203 void BufferImage::MirrorExternal( const RectArea& area )
204 {
205   if( ( mByteStride == mWidth * mBytesPerPixel ) && area.IsEmpty() )
206   {
207     memcpy( mBitmap->GetBuffer(), mExternalBuffer, mBufferSize );
208   }
209   else
210   {
211     UpdateBufferArea( mExternalBuffer, area );
212   }
213 }
214
215 void BufferImage::Connect()
216 {
217   if ( !mConnectionCount++ )
218   {
219     RectArea area;
220     Update( area );
221   }
222 }
223
224 void BufferImage::Disconnect()
225 {
226   if ( mTicket )
227   {
228     if ( !( --mConnectionCount ) && mReleasePolicy == Dali::Image::UNUSED )
229     {
230       mTicket->RemoveObserver(*this);
231       mTicket.Reset();
232     }
233   }
234 }
235
236 } // namespace Internal
237
238 } // namespace Dali